<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"><title>Spring高级45讲【第二章】：IOC | 狼族少年、血狼</title><meta name="author" content="狼族少年、血狼"><meta name="copyright" content="狼族少年、血狼"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="容器接口以SpringBoot的启动类为例： 123456@SpringBootApplicationpublic class A01&amp;#123;    public static void main(String[] args) &amp;#123;        SpringApplication.run(A01.class, args);    &amp;#125;&amp;#125;  容器启动的run()方法是">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring高级45讲【第二章】：IOC">
<meta property="og:url" content="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC.html">
<meta property="og:site_name" content="狼族少年、血狼">
<meta property="og:description" content="容器接口以SpringBoot的启动类为例： 123456@SpringBootApplicationpublic class A01&amp;#123;    public static void main(String[] args) &amp;#123;        SpringApplication.run(A01.class, args);    &amp;#125;&amp;#125;  容器启动的run()方法是">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg">
<meta property="article:published_time" content="2023-04-15T12:12:45.000Z">
<meta property="article:modified_time" content="2023-04-15T12:53:13.666Z">
<meta property="article:author" content="狼族少年、血狼">
<meta property="article:tag" content="spring">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg"><link rel="shortcut icon" href="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png"><link rel="canonical" href="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/db.json","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: true,
  }
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Spring高级45讲【第二章】：IOC',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-04-15 20:53:13'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pace-js/themes/blue/pace-theme-minimal.min.css"/><script src="https://cdn.jsdelivr.net/npm/pace-js/pace.min.js"></script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/gallery/"><i class="fa-fw fas fa-images"></i><span> 画廊</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-paper-plane"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg')"><nav id="nav"><span id="blog-info"><a href="/" title="狼族少年、血狼"><span class="site-name">狼族少年、血狼</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/gallery/"><i class="fa-fw fas fa-images"></i><span> 画廊</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-paper-plane"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Spring高级45讲【第二章】：IOC</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-04-15T12:12:45.000Z" title="发表于 2023-04-15 20:12:45">2023-04-15</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-04-15T12:53:13.666Z" title="更新于 2023-04-15 20:53:13">2023-04-15</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/">原理探究</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">16.3k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>80分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="Spring高级45讲【第二章】：IOC"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="容器接口"><a href="#容器接口" class="headerlink" title="容器接口"></a>容器接口</h1><p>以<code>SpringBoot</code>的启动类为例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A01</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        SpringApplication.run(A01.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>容器启动的<code>run()</code>方法是有返回值的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> SpringApplication.run(A01.class, args);</span><br></pre></td></tr></table></figure>

<p>在 IDEA 中使用快捷键Ctrl +Alt +U查看 <code>ConfigurableApplicationContext</code> 类的类图:</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/1.png" alt="img"></p>
<p><code>ConfigurableApplicationContext</code>接口继承了<code>ApplicationContext</code>接口，而</p>
<p><code>ApplicationContext </code>接口又间接地继承了<code>BeanFactory </code>接口，除此之外还继承了其他很多接口，相当于对<code>BeanFactory </code>进行了拓展。</p>
<p>到底什么是 <code>BeanFactory</code>？</p>
<ol>
<li>它是 <code>ApplicationContext</code> 的父接口</li>
<li>它才是 <code>Spring</code> 的核心容器, 主要的 <code>ApplicationContext</code> 实现都<strong>组合</strong>了它的功能</li>
</ol>
<p>举一个例子：</p>
<p>使用<code>context</code>根据名称获取<code>Bean</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> context.getBean(<span class="string">&quot;Bean&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>Ctrl +Alt +B查看实现类：</p>
<p>进入到了<code>AbstractApplicationContext</code>类中的方法，我们发现首先获取<code>BeanFactory</code>，再调用<code>BeanFactory</code>的<code>getBean()</code>方法获取<code>Bean</code>，说明<code>BeanFactory</code>更加核心。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">getBean</span><span class="params">(String name)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">    <span class="built_in">this</span>.assertBeanFactoryActive();</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.getBeanFactory().getBean(name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="BeanFactory的功能"><a href="#BeanFactory的功能" class="headerlink" title="BeanFactory的功能"></a>BeanFactory的功能</h2><p>进入<code>BeanFactory</code>接口，在IDEA中使用快捷键Ctrl + F12查看这个接口中所有的方法定义:</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/2.png" alt="img"></p>
<p><code>BeanFactory</code>能干点啥？</p>
<ol>
<li>表面上只有<code>getBean()</code>功能</li>
<li>实际上<strong>控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能</strong>, 都由它的实现类提供</li>
</ol>
<p>打开 <code>BeanFactory</code> 的实现类 <code>DefaultListableBeanFactory</code>，查看其类图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/3.png" alt="img"></p>
<p><code>DefaultListableBeanFactory</code>实现了<code>BeanFactory </code>接口，它能管理<code>Spring</code>中所有的<code>Bean</code>，当然也包含<code>Spring</code>容器中的那些单例对象。</p>
<p><code>DefaultListableBeanFactory</code>还继承了<code>DefaultSingletonBeanRegistry</code>类，这个类就是用来管理<code>Spring </code>容器中的单例对象。</p>
<p>在IDEA提供的类图中选中 <code>DefaultSingletonBeanRegistry</code>，然后按下F4进入这个类。它有一个<code>Map</code>类型的成员变量<code>singleton0bjects </code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, Object&gt; singletonObjects = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span>(<span class="number">256</span>);</span><br></pre></td></tr></table></figure>

<p><code>Map</code>的<code>key</code>就是<code>Bean</code>的名字，而<code>value</code>是对应的<code>Bean</code>，即单例对象。</p>
<p>现有如下两个<code>Bean</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Component1</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Component2</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看<code>singletonObjects</code>中是否存在这两个Bean的信息:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 通过反射获取字段</span></span><br><span class="line"><span class="type">Field</span> <span class="variable">singletonObjects</span> <span class="operator">=</span> DefaultSingletonBeanRegistry.class.getDeclaredField(<span class="string">&quot;singletonObjects&quot;</span>);</span><br><span class="line">singletonObjects.setAccessible(<span class="literal">true</span>);</span><br><span class="line"><span class="type">ConfigurableListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> context.getBeanFactory();</span><br><span class="line">Map&lt;String, Object&gt; map = (Map&lt;String, Object&gt;) singletonObjects.get(beanFactory);</span><br><span class="line">map.entrySet().stream().filter(e -&gt; e.getKey().startsWith(<span class="string">&quot;component&quot;</span>))</span><br><span class="line">        .forEach(e -&gt; &#123;</span><br><span class="line">            System.out.println(e.getKey() + <span class="string">&quot;=&quot;</span> + e.getValue());</span><br><span class="line">        &#125;);</span><br></pre></td></tr></table></figure>

<p>运行main()方法后，控制台打印出:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">component1=com.itheima.a01.Component1@59498d94</span><br><span class="line">component2=com.itheima.a01.Component2@35bfa1bb</span><br></pre></td></tr></table></figure>

<h2 id="ApplicationContext的扩展功能"><a href="#ApplicationContext的扩展功能" class="headerlink" title="ApplicationContext的扩展功能"></a>ApplicationContext的扩展功能</h2><p>回顾<code>ConfigurableApplicationContext</code>类的类图:</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/4.png" alt="img"></p>
<p><code>ApplicationContext</code>除了继承<code>BeanFactory</code>外，还继承了∶</p>
<ul>
<li><code>MessageSource</code>：使其具备处理国际化资源的能力</li>
<li><code>ResourcePatternResolver</code>：使其具备使用通配符进行资源匹配的能力</li>
<li><code>EnvironmentCapable</code>：使其具备读取<code>Spring</code>环境信息、配置文件信息的能力</li>
<li><code>ApplicationEventPublisher</code>：使其具备发布事件的能力</li>
</ul>
<h3 id="MessageSource"><a href="#MessageSource" class="headerlink" title="MessageSource"></a>MessageSource</h3><p><code>MessageSource</code>具备处理国际化资源的能力。</p>
<p>在<code>SpringBoot</code>项目的<code>resources</code>目录下创建<code>messages.properties</code>、<code>messages_en.properties</code>、</p>
<p><code>messages_ja.properties</code>、<code>messages_zh.properties</code>四个国际化文件，除<code>messages.properties</code>外，其余三个文件内容如下:</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">hi</span>=<span class="string">Hello</span></span><br><span class="line"><span class="attr">hi</span>=<span class="string">こんにちは</span></span><br><span class="line"><span class="attr">hi</span>=<span class="string">你好</span></span><br></pre></td></tr></table></figure>

<p>测试<code>MessageSource</code>接口中<code>getMessage()</code>方法的使用:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(context.getMessage(<span class="string">&quot;hi&quot;</span>, <span class="literal">null</span>, Locale.CHINA));</span><br><span class="line">System.out.println(context.getMessage(<span class="string">&quot;hi&quot;</span>, <span class="literal">null</span>, Locale.ENGLISH));</span><br><span class="line">System.out.println(context.getMessage(<span class="string">&quot;hi&quot;</span>, <span class="literal">null</span>, Locale.JAPANESE));</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法后，控制台打印出:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">你好</span><br><span class="line">Hello</span><br><span class="line">こんにちは</span><br></pre></td></tr></table></figure>

<p>国际化资源由 <code>ResourceBundleMessageSource</code> 进行处理，我们也可以使用”干净”的<code>Spring</code>容器<code>GenericApplicationcontext</code>，但需要手动注册<code>MessageSource</code>类型的<code>Bean</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestMessageSource</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line"></span><br><span class="line">        context.registerBean(<span class="string">&quot;messageSource&quot;</span>, MessageSource.class, () -&gt; &#123;</span><br><span class="line">            <span class="type">ResourceBundleMessageSource</span> <span class="variable">ms</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ResourceBundleMessageSource</span>();</span><br><span class="line">            ms.setDefaultEncoding(<span class="string">&quot;utf-8&quot;</span>);</span><br><span class="line">            ms.setBasename(<span class="string">&quot;messages&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> ms;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        context.refresh();</span><br><span class="line"></span><br><span class="line">        System.out.println(context.getMessage(<span class="string">&quot;hi&quot;</span>, <span class="literal">null</span>, Locale.ENGLISH));</span><br><span class="line">        System.out.println(context.getMessage(<span class="string">&quot;hi&quot;</span>, <span class="literal">null</span>, Locale.CHINESE));</span><br><span class="line">        System.out.println(context.getMessage(<span class="string">&quot;hi&quot;</span>, <span class="literal">null</span>, Locale.JAPANESE));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法后，控制台打印出:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">你好</span><br><span class="line">Hello</span><br><span class="line">こんにちは</span><br></pre></td></tr></table></figure>

<h3 id="ResourcePatternResolver"><a href="#ResourcePatternResolver" class="headerlink" title="ResourcePatternResolver"></a>ResourcePatternResolver</h3><p><code>ResourcePatternResolver</code>具备使用通配符进行资源匹配的能力。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 加载类路径下的 resource</span></span><br><span class="line">Resource[] resourceList = context.getResources(<span class="string">&quot;classpath:application.properties&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (Resource resource : resourceList) &#123;</span><br><span class="line">    System.out.println(resource);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用classpath*可以加载jar里类路径下的 resource</span></span><br><span class="line">Resource[] resources = context.getResources(<span class="string">&quot;classpath*:META-INF/spring.factories&quot;</span>);</span><br><span class="line"><span class="keyword">for</span> (Resource resource : resources) &#123;</span><br><span class="line">    System.out.println(resource);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">class path resource [application.properties]</span><br><span class="line">URL [file:/F:/Java/%e9%bb%91%e9%a9%ac%e5%85%a8%e5%a5%97java%e6%95%99%e7%a8%8b/%e7%ac%ac2%e9%98%b6%e6%ae%b5%e4%bc%81%e4%b8%9a%e7%ba%a7%e5%bc%80%e5%8f%91%e2%80%94%e5%9f%ba%e7%a1%80%e6%a1%86%e6%9e%b6/7%e3%80%81spring%e9%ab%98%e7%ba%a745%e8%ae%b2/%e4%bb%a3%e7%a0%81/%e4%bb%a3%e7%a0%81/show/target/classes/META-INF/spring.factories]</span><br><span class="line">URL [jar:file:/C:/Users/WolfMan/.m2/repository/com/alibaba/druid-spring-boot-starter/1.2.8/druid-spring-boot-starter-1.2.8.jar!/META-INF/spring.factories]</span><br><span class="line">URL [jar:file:/C:/Users/WolfMan/.m2/repository/org/springframework/spring-test/5.3.10/spring-test-5.3.10.jar!/META-INF/spring.factories]</span><br><span class="line">URL [jar:file:/C:/Users/WolfMan/.m2/repository/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]</span><br><span class="line">URL [jar:file:/C:/Users/WolfMan/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]</span><br><span class="line">URL [jar:file:/C:/Users/WolfMan/.m2/repository/org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.2.0/mybatis-spring-boot-autoconfigure-2.2.0.jar!/META-INF/spring.factories]</span><br><span class="line">URL [jar:file:/C:/Users/WolfMan/.m2/repository/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]</span><br></pre></td></tr></table></figure>

<h3 id="EnvironmentCapable"><a href="#EnvironmentCapable" class="headerlink" title="EnvironmentCapable"></a>EnvironmentCapable</h3><p><code>EnvironmentCapable</code>其具备读取<code>Spring</code>环境信息、配置文件信息的能力 。</p>
<p><code>java_home</code>是从环境变量中读取, <code>properties.name</code>则是从<code>application.yml</code>配置文件中读取。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(context.getEnvironment().getProperty(<span class="string">&quot;java_home&quot;</span>));</span><br><span class="line">System.out.println(context.getEnvironment().getProperty(<span class="string">&quot;server.port&quot;</span>));</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">C:\Path\jdk-14.0.1</span><br><span class="line">8080</span><br></pre></td></tr></table></figure>

<h3 id="ApplicationEventPublisher"><a href="#ApplicationEventPublisher" class="headerlink" title="ApplicationEventPublisher"></a>ApplicationEventPublisher</h3><p><code>ApplicationEventPublisher</code>具备发布事件的能力。</p>
<p>注册事件，需要继承<code>ApplicationEvent </code>，<code>source</code>为事件源(谁发的事件)：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserRegisteredEvent</span> <span class="keyword">extends</span> <span class="title class_">ApplicationEvent</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">UserRegisteredEvent</span><span class="params">(Object source)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(source);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用<code>context</code>发送事件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.publishEvent(<span class="keyword">new</span> <span class="title class_">UserRegisteredEvent</span>(context));</span><br></pre></td></tr></table></figure>

<p>再Component中接收事件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Component2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Component2.class);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@EventListener</span>表示事件监听的方法</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">aaa</span><span class="params">(UserRegisteredEvent event)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;&#123;&#125;&quot;</span>, event);</span><br><span class="line">        log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 15:43:30.940 [main] com.itheima.a01.Component2          - com.itheima.a01.UserRegisteredEvent[source=com.itheima.a01.Component1@26e8ff8c]</span><br></pre></td></tr></table></figure>

<p>可以看到<code>component2</code>监听到了事件</p>
<p>事件的发布与监听主要用于解耦，比如用户注册和发送短信。例如component1发送用户注册事件，component2监听事件并发送短信：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Component1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Component1.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationEventPublisher context;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">register</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;用户注册&quot;</span>);</span><br><span class="line">        context.publishEvent(<span class="keyword">new</span> <span class="title class_">UserRegisteredEvent</span>(<span class="built_in">this</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Component2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Component2.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@EventListener</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">aaa</span><span class="params">(UserRegisteredEvent event)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;&#123;&#125;&quot;</span>, event);</span><br><span class="line">        log.debug(<span class="string">&quot;发送短信&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台打印：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 15:43:30.939 [main] com.itheima.a01.Component1          - 用户注册 </span><br><span class="line">[DEBUG] 15:43:30.940 [main] com.itheima.a01.Component2          - com.itheima.a01.UserRegisteredEvent[source=com.itheima.a01.Component1@26e8ff8c] </span><br><span class="line">[DEBUG] 15:43:30.943 [main] com.itheima.a01.Component2          - 发送短信 </span><br></pre></td></tr></table></figure>

<h2 id="容器接口总结"><a href="#容器接口总结" class="headerlink" title="容器接口总结"></a><strong>容器接口总结</strong></h2><ul>
<li><code>BeanFactory</code>与<code>ApplicationContext</code> 并不仅仅是简单接口继承的关系, <code>ApplicationContext</code> 组合并扩展了<code>BeanFactory</code>的功能</li>
<li>又新学一种代码之间解耦途径，即通过事件发布与监听</li>
</ul>
<h1 id="容器实现"><a href="#容器实现" class="headerlink" title="容器实现"></a>容器实现</h1><h2 id="BeanFactory的实现"><a href="#BeanFactory的实现" class="headerlink" title="BeanFactory的实现"></a>BeanFactory的实现</h2><p>首先了解<code>BeanFactory</code>最重要的实现<code>DefaultListableBeanFactory</code>，使用<code>DefaultListableBeanFactory</code>创建对象，我们需要告诉它<code>Bean</code>的信息，例如<code>Bean</code>的<code>class</code>、<code>scope</code>、初始化、销毁等…</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestBeanFactory</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultListableBeanFactory</span>();</span><br><span class="line">        <span class="comment">// bean 的定义（class, scope, 初始化, 销毁）</span></span><br><span class="line">        <span class="type">AbstractBeanDefinition</span> <span class="variable">beanDefinition</span> <span class="operator">=</span></span><br><span class="line">                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope(<span class="string">&quot;singleton&quot;</span>).getBeanDefinition();</span><br><span class="line">        beanFactory.registerBeanDefinition(<span class="string">&quot;config&quot;</span>, beanDefinition);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (String name : beanFactory.getBeanDefinitionNames()) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Configuration</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> Bean1 <span class="title function_">bean1</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="keyword">public</span> Bean2 <span class="title function_">bean2</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean2</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line">        <span class="meta">@Autowired</span></span><br><span class="line">        <span class="keyword">private</span> Bean2 bean2;</span><br><span class="line">    </span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">Bean1</span><span class="params">()</span> &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;构造 Bean1()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">        <span class="keyword">public</span> Bean2 <span class="title function_">getBean2</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> bean2;</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean2.class);</span><br><span class="line">    </span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">Bean2</span><span class="params">()</span> &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;构造 Bean2()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">config</span><br></pre></td></tr></table></figure>

<p>通过上面的运行示例我们发现，即使<code>Config</code>类上添加了<code>@Configuration</code>注解，其内部也有两个添加了<code>@Bean</code>注解的方法，<code>beanFactory</code>中也只有一个<code>Bean</code>实例。说明<code>DefaultListableBeanFactory</code>本身不具有解析注解的能力。</p>
<p>我们可以通过<code>AnnotationConfigUtils</code>工具类给<code>DefaultListableBeanFactory</code>添加后处理器，以扩展<code>DefaultListableBeanFactory</code>的功能。</p>
<p>我们给<code>DefaultListableBeanFactory</code>添加后处理器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 给 BeanFactory 添加一些常用的后处理器</span></span><br><span class="line">AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);</span><br></pre></td></tr></table></figure>

<p>再次查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">config</span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br></pre></td></tr></table></figure>

<p>我们发现多了很多的<code>Bean</code>，其中<code>org.springframework.context.annotation.internalConfigurationAnnotationProcessor</code>就是用来处理<code>@Configuration</code>、<code>@Bean</code>等注解的类。</p>
<p><code>AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory)</code>只是给<code>beanFactory</code>添加了后处理器，但是没有使用这些处理器的功能，下面我们获取这些处理器，并且使用它们：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// BeanFactory 后处理器主要功能，补充了一些 bean 定义</span></span><br><span class="line">beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -&gt; &#123;</span><br><span class="line">    beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>再次查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">config</span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br><span class="line">bean1</span><br><span class="line">bean2</span><br></pre></td></tr></table></figure>

<p>我们打印了<code>bean1</code>和<code>bean2</code>，说明注解已经被解析并且生效。</p>
<p>我们执行以下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(beanFactory.getBean(Bean1.class).getBean2());</span><br></pre></td></tr></table></figure>

<p>查看控制台打印：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">config</span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br><span class="line">bean1</span><br><span class="line">bean2</span><br><span class="line">[DEBUG] 22:14:07.212 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1() </span><br><span class="line">null</span><br></pre></td></tr></table></figure>

<p>发现虽然调用了<code>Bean1</code>的构造方法，但是<code>Bean2</code>却没有被注入，说明此时的<code>@Autowired</code>并没有生效。其实依赖注入的功能是由<code>Bean</code>的后处理器(注意与<code>BeanFactory</code>的后处理器区分)来处理的。例如：</p>
<ul>
<li><code>internalAutowiredAnnotationProcessor</code>：解析<code>@Autowired</code>注解。</li>
<li><code>internalCommonAnnotationProcessor</code>：解析<code>@Resource</code>注解</li>
</ul>
<p>我们使用<code>Bean</code>的后处理器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...</span></span><br><span class="line">beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">config</span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br><span class="line">bean1</span><br><span class="line">bean2</span><br><span class="line">[DEBUG] 22:26:30.567 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1() </span><br><span class="line">[DEBUG] 22:26:30.591 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2() </span><br><span class="line">com.itheima.a02.TestBeanFactory$Bean2@795509d9</span><br></pre></td></tr></table></figure>

<p>我们发现<code>Bean2</code>成功被注入到了<code>Bean1</code>中。</p>
<p>通过以上示例我们发现，只有<code>getBean()</code>并使用<code>Bean</code>的时候<code>spring</code>才会去初始化真正的实例。</p>
<p>说明只有在我们用到实例对象的时候，<code>spring</code>才会去实例化这些对象，有延迟加载的效果。对于单例对象，我们一般更希望，<code>spring</code>在初始化时就给我们创建这些对象，可以使用<code>preInstantiateSingletons()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">beanFactory.preInstantiateSingletons(); <span class="comment">// 准备好所有单例</span></span><br><span class="line">System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; &quot;</span>);</span><br><span class="line">System.out.println(beanFactory.getBean(Bean1.class).getBean2());</span><br></pre></td></tr></table></figure>

<p>观察控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line">[DEBUG] 22:36:13.682 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1() </span><br><span class="line">[DEBUG] 22:36:13.702 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2() </span><br><span class="line">&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; </span><br><span class="line">com.itheima.a02.TestBeanFactory$Bean2@196a42c3</span><br></pre></td></tr></table></figure>

<p>我们发现在调用<code>beanFactory.preInstantiateSingletons()</code>之后就已经调用了<code>Bean1</code>和<code>Bean2</code>的构造方法，实现了预先加载的功能。</p>
<p>我们进入<code>AnnotationConfigUtils.registerAnnotationConfigProcessors()</code>方法中，</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">registerAnnotationConfigProcessors</span><span class="params">(BeanDefinitionRegistry registry)</span> &#123;</span><br><span class="line">    registerAnnotationConfigProcessors(registry, (Object)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再进入<code>registerAnnotationConfigProcessors(registry, (Object)null)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> Set&lt;BeanDefinitionHolder&gt; <span class="title function_">registerAnnotationConfigProcessors</span><span class="params">(BeanDefinitionRegistry registry, <span class="meta">@Nullable</span> Object source)</span> &#123;</span><br><span class="line">    <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> unwrapDefaultListableBeanFactory(registry);</span><br><span class="line">    <span class="keyword">if</span> (beanFactory != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!(beanFactory.getDependencyComparator() <span class="keyword">instanceof</span> AnnotationAwareOrderComparator)) &#123;</span><br><span class="line">            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!(beanFactory.getAutowireCandidateResolver() <span class="keyword">instanceof</span> ContextAnnotationAutowireCandidateResolver)) &#123;</span><br><span class="line">            beanFactory.setAutowireCandidateResolver(<span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Set&lt;BeanDefinitionHolder&gt; beanDefs = <span class="keyword">new</span> <span class="title class_">LinkedHashSet</span>(<span class="number">8</span>);</span><br><span class="line">    RootBeanDefinition def;</span><br><span class="line">    <span class="keyword">if</span> (!registry.containsBeanDefinition(<span class="string">&quot;org.springframework.context.annotation.internalConfigurationAnnotationProcessor&quot;</span>)) &#123;</span><br><span class="line">        def = <span class="keyword">new</span> <span class="title class_">RootBeanDefinition</span>(ConfigurationClassPostProcessor.class);</span><br><span class="line">        def.setSource(source);</span><br><span class="line">        beanDefs.add(registerPostProcessor(registry, def, <span class="string">&quot;org.springframework.context.annotation.internalConfigurationAnnotationProcessor&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!registry.containsBeanDefinition(<span class="string">&quot;org.springframework.context.annotation.internalAutowiredAnnotationProcessor&quot;</span>)) &#123;</span><br><span class="line">        def = <span class="keyword">new</span> <span class="title class_">RootBeanDefinition</span>(AutowiredAnnotationBeanPostProcessor.class);</span><br><span class="line">        def.setSource(source);</span><br><span class="line">        beanDefs.add(registerPostProcessor(registry, def, <span class="string">&quot;org.springframework.context.annotation.internalAutowiredAnnotationProcessor&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (jsr250Present &amp;&amp; !registry.containsBeanDefinition(<span class="string">&quot;org.springframework.context.annotation.internalCommonAnnotationProcessor&quot;</span>)) &#123;</span><br><span class="line">        def = <span class="keyword">new</span> <span class="title class_">RootBeanDefinition</span>(CommonAnnotationBeanPostProcessor.class);</span><br><span class="line">        def.setSource(source);</span><br><span class="line">        beanDefs.add(registerPostProcessor(registry, def, <span class="string">&quot;org.springframework.context.annotation.internalCommonAnnotationProcessor&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (jpaPresent &amp;&amp; !registry.containsBeanDefinition(<span class="string">&quot;org.springframework.context.annotation.internalPersistenceAnnotationProcessor&quot;</span>)) &#123;</span><br><span class="line">        def = <span class="keyword">new</span> <span class="title class_">RootBeanDefinition</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            def.setBeanClass(ClassUtils.forName(<span class="string">&quot;org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor&quot;</span>, AnnotationConfigUtils.class.getClassLoader()));</span><br><span class="line">        &#125; <span class="keyword">catch</span> (ClassNotFoundException var6) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(<span class="string">&quot;Cannot load optional framework class: org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor&quot;</span>, var6);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        def.setSource(source);</span><br><span class="line">        beanDefs.add(registerPostProcessor(registry, def, <span class="string">&quot;org.springframework.context.annotation.internalPersistenceAnnotationProcessor&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!registry.containsBeanDefinition(<span class="string">&quot;org.springframework.context.event.internalEventListenerProcessor&quot;</span>)) &#123;</span><br><span class="line">        def = <span class="keyword">new</span> <span class="title class_">RootBeanDefinition</span>(EventListenerMethodProcessor.class);</span><br><span class="line">        def.setSource(source);</span><br><span class="line">        beanDefs.add(registerPostProcessor(registry, def, <span class="string">&quot;org.springframework.context.event.internalEventListenerProcessor&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!registry.containsBeanDefinition(<span class="string">&quot;org.springframework.context.event.internalEventListenerFactory&quot;</span>)) &#123;</span><br><span class="line">        def = <span class="keyword">new</span> <span class="title class_">RootBeanDefinition</span>(DefaultEventListenerFactory.class);</span><br><span class="line">        def.setSource(source);</span><br><span class="line">        beanDefs.add(registerPostProcessor(registry, def, <span class="string">&quot;org.springframework.context.event.internalEventListenerFactory&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> beanDefs;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里注册了很多后处理器，其中包括解析<code>@Autowired</code>注解的<code>AutowiredAnnotationBeanPostProcessor</code>以及解析<code>@Resource</code>注解的<code>CommonAnnotationBeanPostProcessor</code>。</p>
<p>那么在依赖注入的时候既加了<code>@Autowired</code>又加了<code>@Resource</code>，谁会优先生效呢？准备以下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Inter</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean3</span> <span class="keyword">implements</span> <span class="title class_">Inter</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean4</span> <span class="keyword">implements</span> <span class="title class_">Inter</span> &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean1</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;构造 Bean1()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Bean2 bean2;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Bean2 <span class="title function_">getBean2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> bean2;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="meta">@Resource(name = &quot;bean4&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Inter bean3;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Inter <span class="title function_">getInter</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> bean3;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean2.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean2</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;构造 Bean2()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>@Autowired</code>首先判断依赖注入的类型，如果有同类型的<code>Bean</code>，那么再判断属性的名称，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> Inter bean3;</span><br></pre></td></tr></table></figure>

<p>将会注入Bean3：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a02.TestBeanFactory$Bean3@2af004b</span><br></pre></td></tr></table></figure>

<p><code>@Resource</code>首先判断名称，如果没有给<code>name</code>属性的话在判断类型，如果有多个类型再判断属性的名称，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource(name = &quot;bean4&quot;)</span></span><br><span class="line"><span class="keyword">private</span> Inter bean3;</span><br></pre></td></tr></table></figure>

<p>将会注入Bean4：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a02.TestBeanFactory$Bean4@663c9e7a</span><br></pre></td></tr></table></figure>

<p>当同时加<code>@Autowired</code>与<code>@Resource(name = &quot;bean4&quot;)</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="meta">@Resource(name = &quot;bean4&quot;)</span></span><br><span class="line"><span class="keyword">private</span> Inter bean3;</span><br></pre></td></tr></table></figure>

<p>我们发现注入的是Bean3：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.itheima.a02.TestBeanFactory$Bean3@2af004b</span><br></pre></td></tr></table></figure>

<p>为什么呢？</p>
<p>由于<code>Bean</code>处理器与其注册的顺序有关，<code>AutowiredAnnotationBeanPostProcessor</code>比<code>CommonAnnotationBeanPostProcessor</code>优先注册，因此优先级更高。</p>
<p>我们可以编码查看：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;&gt;&gt;&gt;&gt;&quot;</span> + beanPostProcessor);</span><br><span class="line">            beanFactory.addBeanPostProcessor(beanPostProcessor);</span><br><span class="line">        &#125;);</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@1e1a0406</span><br><span class="line">&gt;&gt;&gt;&gt;org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@3cebbb30</span><br></pre></td></tr></table></figure>

<p>我们可以通过添加比较器的方式手动调整Bean的顺序：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()</span><br><span class="line">        .sorted(beanFactory.getDependencyComparator())</span><br><span class="line">        .forEach(beanPostProcessor -&gt; &#123;</span><br><span class="line">            System.out.println(&quot;&gt;&gt;&gt;&gt;&quot; + beanPostProcessor);</span><br><span class="line">            beanFactory.addBeanPostProcessor(beanPostProcessor);</span><br><span class="line">        &#125;);</span><br></pre></td></tr></table></figure>

<p>重新运行代码，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt;&gt;org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@6253c26</span><br><span class="line">&gt;&gt;&gt;&gt;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@49049a04</span><br><span class="line">...</span><br><span class="line">com.itheima.a02.TestBeanFactory$Bean4@548d708a</span><br></pre></td></tr></table></figure>

<p>我们发现处理器的顺序发生了改变，同时注入的<code>Bean</code>对象也改变了。</p>
<p>我们通过<code>beanFactory.getDependencyComparator()</code>获取了一个比较器，说明在<code>beanFactory</code>初始化的时候设置了比较器。其实比较器是通过<code>AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory)</code>设置的，进入方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">registerAnnotationConfigProcessors</span><span class="params">(BeanDefinitionRegistry registry)</span> &#123;</span><br><span class="line">    registerAnnotationConfigProcessors(registry, (Object)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再次进入<code>registerAnnotationConfigProcessors(registry, (Object)null)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> unwrapDefaultListableBeanFactory(registry);</span><br><span class="line"><span class="keyword">if</span> (beanFactory != <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!(beanFactory.getDependencyComparator() <span class="keyword">instanceof</span> AnnotationAwareOrderComparator)) &#123;</span><br><span class="line">        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!(beanFactory.getAutowireCandidateResolver() <span class="keyword">instanceof</span> ContextAnnotationAutowireCandidateResolver)) &#123;</span><br><span class="line">        beanFactory.setAutowireCandidateResolver(<span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//....</span></span><br></pre></td></tr></table></figure>

<p>加粗部分就是在设置比较器，我们进入<code>AnnotationAwareOrderComparator.INSTANCE</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">AnnotationAwareOrderComparator</span> <span class="variable">INSTANCE</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationAwareOrderComparator</span>();</span><br></pre></td></tr></table></figure>

<p>发现是一个通过”饿汉式”初始化的比较器。</p>
<p>我们发现<code>AnnotationAwareOrderComparator </code>继承了<code>OrderComparator</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AnnotationAwareOrderComparator</span> <span class="keyword">extends</span> <span class="title class_">OrderComparator</span></span><br></pre></td></tr></table></figure>

<p>进入<code>OrderComparator</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OrderComparator</span> <span class="keyword">implements</span> <span class="title class_">Comparator</span>&lt;Object&gt;</span><br></pre></td></tr></table></figure>

<p>发现<code>OrderComparator</code>实现了<code>Comparator&lt;Object&gt;</code>接口，查看<code>compare()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(<span class="meta">@Nullable</span> Object o1, <span class="meta">@Nullable</span> Object o2)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.doCompare(o1, o2, (OrderSourceProvider)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.doCompare(o1, o2, (OrderSourceProvider)null)</code>方法中：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="type">int</span> <span class="title function_">doCompare</span><span class="params">(<span class="meta">@Nullable</span> Object o1, <span class="meta">@Nullable</span> Object o2, <span class="meta">@Nullable</span> OrderSourceProvider sourceProvider)</span> &#123;</span><br><span class="line">    <span class="type">boolean</span> <span class="variable">p1</span> <span class="operator">=</span> o1 <span class="keyword">instanceof</span> PriorityOrdered;</span><br><span class="line">    <span class="type">boolean</span> <span class="variable">p2</span> <span class="operator">=</span> o2 <span class="keyword">instanceof</span> PriorityOrdered;</span><br><span class="line">    <span class="keyword">if</span> (p1 &amp;&amp; !p2) &#123;</span><br><span class="line">        <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (p2 &amp;&amp; !p1) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">i1</span> <span class="operator">=</span> <span class="built_in">this</span>.getOrder(o1, sourceProvider);</span><br><span class="line">        <span class="type">int</span> <span class="variable">i2</span> <span class="operator">=</span> <span class="built_in">this</span>.getOrder(o2, sourceProvider);</span><br><span class="line">        <span class="keyword">return</span> Integer.compare(i1, i2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看<code>AutowiredAnnotationBeanPostProcessor </code>类图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/5.png" alt="img"></p>
<p>查看<code>CommonAnnotationBeanPostProcessor </code>类图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/6.png" alt="img"></p>
<p>因为<code>AutowiredAnnotationBeanPostProcessor </code>和<code>CommonAnnotationBeanPostProcessor </code>都直接或间接地实现了<code>PriorityOrdered</code>接口，因此p1和p2都为true。</p>
<p>接下来进入<code>this.getOrder()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">(<span class="meta">@Nullable</span> Object obj, <span class="meta">@Nullable</span> OrderSourceProvider sourceProvider)</span> &#123;</span><br><span class="line">    <span class="type">Integer</span> <span class="variable">order</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (obj != <span class="literal">null</span> &amp;&amp; sourceProvider != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="type">Object</span> <span class="variable">orderSource</span> <span class="operator">=</span> sourceProvider.getOrderSource(obj);</span><br><span class="line">        <span class="keyword">if</span> (orderSource != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (orderSource.getClass().isArray()) &#123;</span><br><span class="line">                Object[] var5 = ObjectUtils.toObjectArray(orderSource);</span><br><span class="line">                <span class="type">int</span> <span class="variable">var6</span> <span class="operator">=</span> var5.length;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">var7</span> <span class="operator">=</span> <span class="number">0</span>; var7 &lt; var6; ++var7) &#123;</span><br><span class="line">                    <span class="type">Object</span> <span class="variable">source</span> <span class="operator">=</span> var5[var7];</span><br><span class="line">                    order = <span class="built_in">this</span>.findOrder(source);</span><br><span class="line">                    <span class="keyword">if</span> (order != <span class="literal">null</span>) &#123;</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                order = <span class="built_in">this</span>.findOrder(orderSource);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> order != <span class="literal">null</span> ? order : <span class="built_in">this</span>.getOrder(obj);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>由于<code>sourceProvider==null</code>，因此进入<code>this.getOrder()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">(<span class="meta">@Nullable</span> Object obj)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (obj != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="type">Integer</span> <span class="variable">order</span> <span class="operator">=</span> <span class="built_in">this</span>.findOrder(obj);</span><br><span class="line">        <span class="keyword">if</span> (order != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> order;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> Integer.MAX_VALUE;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.findOrder(obj)</code>方法，实际上是进入<code>AnnotationAwareOrderComparator</code>的<code>findOrder(obj)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">protected</span> Integer <span class="title function_">findOrder</span><span class="params">(Object obj)</span> &#123;</span><br><span class="line">    <span class="type">Integer</span> <span class="variable">order</span> <span class="operator">=</span> <span class="built_in">super</span>.findOrder(obj);</span><br><span class="line">    <span class="keyword">return</span> order != <span class="literal">null</span> ? order : <span class="built_in">this</span>.findOrderFromAnnotation(obj);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>首先调用父类<code>OrderComparator</code>的<code>findOrder(obj)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">protected</span> Integer <span class="title function_">findOrder</span><span class="params">(Object obj)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> obj <span class="keyword">instanceof</span> Ordered ? ((Ordered)obj).getOrder() : <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>AutowiredAnnotationBeanPostProcessor </code>和<code>CommonAnnotationBeanPostProcessor </code>都直接或间接地实现了<code>PriorityOrdered</code>接口，而<code>PriorityOrdered</code>继承了<code>Ordered </code>接口，因此调用实现类的<code>getOrder()</code>方法。</p>
<p>查看<code>AutowiredAnnotationBeanPostProcessor </code>的<code>getOrder()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="type">int</span> <span class="variable">order</span> <span class="operator">=</span> <span class="number">2147483645</span>;</span><br><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.order;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>查看<code>CommonAnnotationBeanPostProcessor</code>的<code>setOrder()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.setOrder(<span class="number">2147483644</span>);</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setOrder</span><span class="params">(<span class="type">int</span> order)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.order = order;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因此根据<code>AnnotationAwareOrderComparator</code>排序<code>CommonAnnotationBeanPostProcessor</code>要小于<code>AutowiredAnnotationBeanPostProcessor</code>。</p>
<p><code>BeanFactory</code>和<code>SpringApplicationContext</code>的区别？</p>
<ol>
<li>不会主动调用<code>BeanFactory</code>后处理器</li>
<li>不会主动添加<code>Bean</code>后处理器</li>
<li>不会主动初始化单例</li>
<li>不会解析<code>beanFactory</code></li>
<li>不会解析<code>$&#123;&#125;</code>与<code>#&#123;&#125;</code>等表达式</li>
<li><code>bean</code>后处理器会有排序的逻辑</li>
</ol>
<h2 id="ApplicationContext的实现"><a href="#ApplicationContext的实现" class="headerlink" title="ApplicationContext的实现"></a>ApplicationContext的实现</h2><p>接下来介绍<code>ApplicationContext</code>四个比较典型的实现类：</p>
<ul>
<li><code>ClassPathXmlApplicationContext</code>：️较为经典的容器, 基于<code>classpath</code>下<code>xml</code>格式的配置文件来创建。</li>
<li><code>FileSystemXmlApplicationContext</code>：基于磁盘路径下<code>xml</code>格式的配置文件来创建。</li>
<li><code>AnnotationConfigApplicationContext</code>：较为经典的容器, 基于<code>java</code>配置类来创建。</li>
<li><code>AnnotationConfigServletWebServerApplicationContext</code>：较为经典的容器, 基于<code>java</code>配置类来创建, 用于<code>web</code>环境。</li>
</ul>
<ol>
<li>ClassPathXmlApplicationContext</li>
</ol>
<p><strong>使用演示</strong></p>
<p>准备两个类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Bean1 bean1;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean1</span><span class="params">(Bean1 bean1)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bean1 = bean1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Bean1 <span class="title function_">getBean1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> bean1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>a02.xml</code>配置文件：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 控制反转, 让 bean1 被 Spring 容器管理 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bean1&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.a02.A02.Bean1&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 控制反转, 让 bean2 被 Spring 容器管理 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bean2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.itheima.a02.A02.Bean2&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 依赖注入, 建立与 bean1 的依赖关系 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;bean1&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;bean1&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>读取<code>classpath</code>下<code>xml</code>格式的配置文件，获取<code>Bean</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ⬇️较为经典的容器, 基于 classpath 下 xml 格式的配置文件来创建</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testClassPathXmlApplicationContext</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">ClassPathXmlApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span></span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;a02.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">        System.out.println(name);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    System.out.println(context.getBean(Bean2.class).getBean1());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bean1</span><br><span class="line">bean2</span><br><span class="line">com.itheima.a02.A02$Bean1@1de5f259</span><br></pre></td></tr></table></figure>

<p>我们发现Bean已经成功地被注入。</p>
<p><strong>源码剖析</strong></p>
<p>首先进入<code>ClassPathXmlApplicationContext</code>的构造方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">ClassPathXmlApplicationContext</span><span class="params">(String configLocation)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">    <span class="built_in">this</span>(<span class="keyword">new</span> <span class="title class_">String</span>[]&#123;configLocation&#125;, <span class="literal">true</span>, (ApplicationContext)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入重载的构造方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">ClassPathXmlApplicationContext</span><span class="params">(String[] configLocations, <span class="type">boolean</span> refresh, <span class="meta">@Nullable</span> ApplicationContext parent)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">    <span class="built_in">super</span>(parent);</span><br><span class="line">    <span class="comment">// 设置xml文件路径</span></span><br><span class="line">    <span class="built_in">this</span>.setConfigLocations(configLocations);</span><br><span class="line">    <span class="keyword">if</span> (refresh) &#123;</span><br><span class="line">        <span class="built_in">this</span>.refresh();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>refresh()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">refresh</span><span class="params">()</span> <span class="keyword">throws</span> BeansException, IllegalStateException &#123;</span><br><span class="line">    <span class="keyword">synchronized</span>(<span class="built_in">this</span>.startupShutdownMonitor) &#123;</span><br><span class="line">        <span class="type">StartupStep</span> <span class="variable">contextRefresh</span> <span class="operator">=</span> <span class="built_in">this</span>.applicationStartup.start(<span class="string">&quot;spring.context.refresh&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.prepareRefresh();</span><br><span class="line">        <span class="type">ConfigurableListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="built_in">this</span>.obtainFreshBeanFactory();</span><br><span class="line">        <span class="built_in">this</span>.prepareBeanFactory(beanFactory);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">       </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们主要关注<code>beanFactory</code>的构造，进入<code>this.obtainFreshBeanFactory()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> ConfigurableListableBeanFactory <span class="title function_">obtainFreshBeanFactory</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.refreshBeanFactory();</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.getBeanFactory();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.refreshBeanFactory()</code>方法，其实进入的是<code>AbstractRefreshableApplicationContext</code>类的<code>refreshBeanFactory()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">refreshBeanFactory</span><span class="params">()</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.hasBeanFactory()) &#123;</span><br><span class="line">        <span class="built_in">this</span>.destroyBeans();</span><br><span class="line">        <span class="built_in">this</span>.closeBeanFactory();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 创建BeanFactory的重要实现类DefaultListableBeanFactory </span></span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="built_in">this</span>.createBeanFactory();</span><br><span class="line">        beanFactory.setSerializationId(<span class="built_in">this</span>.getId());</span><br><span class="line">        <span class="built_in">this</span>.customizeBeanFactory(beanFactory);</span><br><span class="line">        <span class="comment">// 加载BeanDefinitions，会解析spring配置文件(a01.xml)</span></span><br><span class="line">        <span class="built_in">this</span>.loadBeanDefinitions(beanFactory);</span><br><span class="line">        <span class="built_in">this</span>.beanFactory = beanFactory;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException var2) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ApplicationContextException</span>(<span class="string">&quot;I/O error parsing bean definition source for &quot;</span> + <span class="built_in">this</span>.getDisplayName(), var2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.loadBeanDefinitions(beanFactory)</code>，实际上是进入<code>AbstractXmlApplicationContext</code>的<code>loadBeanDefinitions(DefaultListableBeanFactory beanFactory)</code>方法，我们看看spring如何解析配置文件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> BeansException, IOException &#123;</span><br><span class="line">    <span class="comment">// 创建XmlBeanDefinitionReader</span></span><br><span class="line">    <span class="type">XmlBeanDefinitionReader</span> <span class="variable">beanDefinitionReader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">XmlBeanDefinitionReader</span>(beanFactory);</span><br><span class="line">    beanDefinitionReader.setEnvironment(<span class="built_in">this</span>.getEnvironment());</span><br><span class="line">    beanDefinitionReader.setResourceLoader(<span class="built_in">this</span>);</span><br><span class="line">    beanDefinitionReader.setEntityResolver(<span class="keyword">new</span> <span class="title class_">ResourceEntityResolver</span>(<span class="built_in">this</span>));</span><br><span class="line">    <span class="built_in">this</span>.initBeanDefinitionReader(beanDefinitionReader);</span><br><span class="line">    <span class="comment">// 真正加载BeanDefinition的方法</span></span><br><span class="line">    <span class="built_in">this</span>.loadBeanDefinitions(beanDefinitionReader);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.loadBeanDefinitions(beanDefinitionReader)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(XmlBeanDefinitionReader reader)</span> <span class="keyword">throws</span> BeansException, IOException &#123;</span><br><span class="line">    Resource[] configResources = <span class="built_in">this</span>.getConfigResources();</span><br><span class="line">    <span class="keyword">if</span> (configResources != <span class="literal">null</span>) &#123;</span><br><span class="line">        reader.loadBeanDefinitions(configResources);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    String[] configLocations = <span class="built_in">this</span>.getConfigLocations();</span><br><span class="line">    <span class="keyword">if</span> (configLocations != <span class="literal">null</span>) &#123;</span><br><span class="line">        reader.loadBeanDefinitions(configLocations);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>reader.loadBeanDefinitions(configLocations)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(String... locations)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    Assert.notNull(locations, <span class="string">&quot;Location array must not be null&quot;</span>);</span><br><span class="line">    <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">    String[] var3 = locations;</span><br><span class="line">    <span class="type">int</span> <span class="variable">var4</span> <span class="operator">=</span> locations.length;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">var5</span> <span class="operator">=</span> <span class="number">0</span>; var5 &lt; var4; ++var5) &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">location</span> <span class="operator">=</span> var3[var5];</span><br><span class="line">        count += <span class="built_in">this</span>.loadBeanDefinitions(location);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.loadBeanDefinitions(location)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(String location)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.loadBeanDefinitions(location, (Set)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入重载的<code>this.loadBeanDefinitions(location, (Set)null)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(String location, <span class="meta">@Nullable</span> Set&lt;Resource&gt; actualResources)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="type">ResourceLoader</span> <span class="variable">resourceLoader</span> <span class="operator">=</span> <span class="built_in">this</span>.getResourceLoader();</span><br><span class="line">    <span class="keyword">if</span> (resourceLoader == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(<span class="string">&quot;Cannot load bean definitions from location [&quot;</span> + location + <span class="string">&quot;]: no ResourceLoader available&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="type">int</span> count;</span><br><span class="line">        <span class="keyword">if</span> (resourceLoader <span class="keyword">instanceof</span> ResourcePatternResolver) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);</span><br><span class="line">                count = <span class="built_in">this</span>.loadBeanDefinitions(resources);</span><br><span class="line">                <span class="keyword">if</span> (actualResources != <span class="literal">null</span>) &#123;</span><br><span class="line">                    Collections.addAll(actualResources, resources);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.logger.trace(<span class="string">&quot;Loaded &quot;</span> + count + <span class="string">&quot; bean definitions from location pattern [&quot;</span> + location + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> count;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException var6) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(<span class="string">&quot;Could not resolve bean definition resource pattern [&quot;</span> + location + <span class="string">&quot;]&quot;</span>, var6);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//...</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.loadBeanDefinitions(resources)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(Resource... resources)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    Assert.notNull(resources, <span class="string">&quot;Resource array must not be null&quot;</span>);</span><br><span class="line">    <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">    Resource[] var3 = resources;</span><br><span class="line">    <span class="type">int</span> <span class="variable">var4</span> <span class="operator">=</span> resources.length;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">var5</span> <span class="operator">=</span> <span class="number">0</span>; var5 &lt; var4; ++var5) &#123;</span><br><span class="line">        <span class="type">Resource</span> <span class="variable">resource</span> <span class="operator">=</span> var3[var5];</span><br><span class="line">        count += <span class="built_in">this</span>.loadBeanDefinitions((Resource)resource);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.loadBeanDefinitions((Resource)resource)</code>方法，实际上进入的是<code>XmlBeanDefinitionReader</code>的<code>loadBeanDefinitions(Resource resource)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(Resource resource)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.loadBeanDefinitions(<span class="keyword">new</span> <span class="title class_">EncodedResource</span>(resource));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入重载的<code>this.loadBeanDefinitions(new EncodedResource(resource))</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(EncodedResource encodedResource)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    Assert.notNull(encodedResource, <span class="string">&quot;EncodedResource must not be null&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">        <span class="built_in">this</span>.logger.trace(<span class="string">&quot;Loading XML bean definitions from &quot;</span> + encodedResource);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Set&lt;EncodedResource&gt; currentResources = (Set)<span class="built_in">this</span>.resourcesCurrentlyBeingLoaded.get();</span><br><span class="line">    <span class="keyword">if</span> (!currentResources.add(encodedResource)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(<span class="string">&quot;Detected cyclic loading of &quot;</span> + encodedResource + <span class="string">&quot; - check your import definitions!&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="type">int</span> var6;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> encodedResource.getResource().getInputStream();</span><br><span class="line">            <span class="type">Throwable</span> <span class="variable">var4</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="type">InputSource</span> <span class="variable">inputSource</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InputSource</span>(inputStream);</span><br><span class="line">                <span class="keyword">if</span> (encodedResource.getEncoding() != <span class="literal">null</span>) &#123;</span><br><span class="line">                    inputSource.setEncoding(encodedResource.getEncoding());</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                var6 = <span class="built_in">this</span>.doLoadBeanDefinitions(inputSource, encodedResource.getResource());</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable var24) &#123;</span><br><span class="line">                var4 = var24;</span><br><span class="line">                <span class="keyword">throw</span> var24;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="comment">//...</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException var26) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(<span class="string">&quot;IOException parsing XML document from &quot;</span> + encodedResource.getResource(), var26);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="comment">//...</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> var6;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.doLoadBeanDefinitions(inputSource, encodedResource.getResource())</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="type">int</span> <span class="title function_">doLoadBeanDefinitions</span><span class="params">(InputSource inputSource, Resource resource)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">Document</span> <span class="variable">doc</span> <span class="operator">=</span> <span class="built_in">this</span>.doLoadDocument(inputSource, resource);</span><br><span class="line">        <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="built_in">this</span>.registerBeanDefinitions(doc, resource);</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isDebugEnabled()) &#123;</span><br><span class="line">            <span class="built_in">this</span>.logger.debug(<span class="string">&quot;Loaded &quot;</span> + count + <span class="string">&quot; bean definitions from &quot;</span> + resource);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> count;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (BeanDefinitionStoreException var5) &#123;</span><br><span class="line">        <span class="keyword">throw</span> var5;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (SAXParseException var6) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">XmlBeanDefinitionStoreException</span>(resource.getDescription(), <span class="string">&quot;Line &quot;</span> + var6.getLineNumber() + <span class="string">&quot; in XML document from &quot;</span> + resource + <span class="string">&quot; is invalid&quot;</span>, var6);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (SAXException var7) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">XmlBeanDefinitionStoreException</span>(resource.getDescription(), <span class="string">&quot;XML document from &quot;</span> + resource + <span class="string">&quot; is invalid&quot;</span>, var7);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ParserConfigurationException var8) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(resource.getDescription(), <span class="string">&quot;Parser configuration exception parsing XML from &quot;</span> + resource, var8);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException var9) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(resource.getDescription(), <span class="string">&quot;IOException parsing XML document from &quot;</span> + resource, var9);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var10) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(resource.getDescription(), <span class="string">&quot;Unexpected exception parsing XML document from &quot;</span> + resource, var10);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.registerBeanDefinitions(doc, resource)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">registerBeanDefinitions</span><span class="params">(Document doc, Resource resource)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="type">BeanDefinitionDocumentReader</span> <span class="variable">documentReader</span> <span class="operator">=</span> <span class="built_in">this</span>.createBeanDefinitionDocumentReader();</span><br><span class="line">    <span class="type">int</span> <span class="variable">countBefore</span> <span class="operator">=</span> <span class="built_in">this</span>.getRegistry().getBeanDefinitionCount();</span><br><span class="line">    documentReader.registerBeanDefinitions(doc, <span class="built_in">this</span>.createReaderContext(resource));</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.getRegistry().getBeanDefinitionCount() - countBefore;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource))</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">registerBeanDefinitions</span><span class="params">(Document doc, XmlReaderContext readerContext)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.readerContext = readerContext;</span><br><span class="line">    <span class="built_in">this</span>.doRegisterBeanDefinitions(doc.getDocumentElement());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.doRegisterBeanDefinitions(doc.getDocumentElement())</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doRegisterBeanDefinitions</span><span class="params">(Element root)</span> &#123;</span><br><span class="line">    <span class="type">BeanDefinitionParserDelegate</span> <span class="variable">parent</span> <span class="operator">=</span> <span class="built_in">this</span>.delegate;</span><br><span class="line">    <span class="built_in">this</span>.delegate = <span class="built_in">this</span>.createDelegate(<span class="built_in">this</span>.getReaderContext(), root, parent);</span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">this</span>.delegate.isDefaultNamespace(root)) &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">profileSpec</span> <span class="operator">=</span> root.getAttribute(<span class="string">&quot;profile&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (StringUtils.hasText(profileSpec)) &#123;</span><br><span class="line">            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, <span class="string">&quot;,; &quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (!<span class="built_in">this</span>.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isDebugEnabled()) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.logger.debug(<span class="string">&quot;Skipped XML bean definition file due to specified profiles [&quot;</span> + profileSpec + <span class="string">&quot;] not matching: &quot;</span> + <span class="built_in">this</span>.getReaderContext().getResource());</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">this</span>.preProcessXml(root);</span><br><span class="line">    <span class="built_in">this</span>.parseBeanDefinitions(root, <span class="built_in">this</span>.delegate);</span><br><span class="line">    <span class="built_in">this</span>.postProcessXml(root);</span><br><span class="line">    <span class="built_in">this</span>.delegate = parent;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.parseBeanDefinitions(root, this.delegate)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">parseBeanDefinitions</span><span class="params">(Element root, BeanDefinitionParserDelegate delegate)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (delegate.isDefaultNamespace(root)) &#123;</span><br><span class="line">        <span class="type">NodeList</span> <span class="variable">nl</span> <span class="operator">=</span> root.getChildNodes();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; nl.getLength(); ++i) &#123;</span><br><span class="line">            <span class="type">Node</span> <span class="variable">node</span> <span class="operator">=</span> nl.item(i);</span><br><span class="line">            <span class="keyword">if</span> (node <span class="keyword">instanceof</span> Element) &#123;</span><br><span class="line">                <span class="type">Element</span> <span class="variable">ele</span> <span class="operator">=</span> (Element)node;</span><br><span class="line">                <span class="keyword">if</span> (delegate.isDefaultNamespace(ele)) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.parseDefaultElement(ele, delegate);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    delegate.parseCustomElement(ele);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        delegate.parseCustomElement(root);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.parseDefaultElement(ele, delegate)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">parseDefaultElement</span><span class="params">(Element ele, BeanDefinitionParserDelegate delegate)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (delegate.nodeNameEquals(ele, <span class="string">&quot;import&quot;</span>)) &#123;</span><br><span class="line">        <span class="built_in">this</span>.importBeanDefinitionResource(ele);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (delegate.nodeNameEquals(ele, <span class="string">&quot;alias&quot;</span>)) &#123;</span><br><span class="line">        <span class="built_in">this</span>.processAliasRegistration(ele);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (delegate.nodeNameEquals(ele, <span class="string">&quot;bean&quot;</span>)) &#123;</span><br><span class="line">        <span class="built_in">this</span>.processBeanDefinition(ele, delegate);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (delegate.nodeNameEquals(ele, <span class="string">&quot;beans&quot;</span>)) &#123;</span><br><span class="line">        <span class="built_in">this</span>.doRegisterBeanDefinitions(ele);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们可以看到，这里开始解析各种标签，如import、alias、bean等…</p>
<p>进入解析<code>Bean</code>标签的<code>this.processBeanDefinition(ele, delegate)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">processBeanDefinition</span><span class="params">(Element ele, BeanDefinitionParserDelegate delegate)</span> &#123;</span><br><span class="line">    <span class="comment">// 解析bean标签</span></span><br><span class="line">    <span class="type">BeanDefinitionHolder</span> <span class="variable">bdHolder</span> <span class="operator">=</span> delegate.parseBeanDefinitionElement(ele);</span><br><span class="line">    <span class="keyword">if</span> (bdHolder != <span class="literal">null</span>) &#123;</span><br><span class="line">        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//注册BeanDefinition包括名称，类</span></span><br><span class="line">            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, <span class="built_in">this</span>.getReaderContext().getRegistry());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (BeanDefinitionStoreException var5) &#123;</span><br><span class="line">            <span class="built_in">this</span>.getReaderContext().error(<span class="string">&quot;Failed to register bean definition with name &#x27;&quot;</span> + bdHolder.getBeanName() + <span class="string">&quot;&#x27;&quot;</span>, ele, var5);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">this</span>.getReaderContext().fireComponentRegistered(<span class="keyword">new</span> <span class="title class_">BeanComponentDefinition</span>(bdHolder));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>首先进入<code>delegate.parseBeanDefinitionElement(ele)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">public</span> BeanDefinitionHolder <span class="title function_">parseBeanDefinitionElement</span><span class="params">(Element ele)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.parseBeanDefinitionElement(ele, (BeanDefinition)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再进入重载的<code>this.parseBeanDefinitionElement(ele, (BeanDefinition)null)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">public</span> BeanDefinitionHolder <span class="title function_">parseBeanDefinitionElement</span><span class="params">(Element ele, <span class="meta">@Nullable</span> BeanDefinition containingBean)</span> &#123;</span><br><span class="line">    <span class="comment">// 获取id，我们这里的id为bean1</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">id</span> <span class="operator">=</span> ele.getAttribute(<span class="string">&quot;id&quot;</span>);</span><br><span class="line">    <span class="comment">// 获取名称</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">nameAttr</span> <span class="operator">=</span> ele.getAttribute(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">    List&lt;String&gt; aliases = <span class="keyword">new</span> <span class="title class_">ArrayList</span>();</span><br><span class="line">    <span class="keyword">if</span> (StringUtils.hasLength(nameAttr)) &#123;</span><br><span class="line">        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, <span class="string">&quot;,; &quot;</span>);</span><br><span class="line">        aliases.addAll(Arrays.asList(nameArr));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">String</span> <span class="variable">beanName</span> <span class="operator">=</span> id;</span><br><span class="line">    <span class="keyword">if</span> (!StringUtils.hasText(id) &amp;&amp; !aliases.isEmpty()) &#123;</span><br><span class="line">        beanName = (String)aliases.remove(<span class="number">0</span>);</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">            <span class="built_in">this</span>.logger.trace(<span class="string">&quot;No XML &#x27;id&#x27; specified - using &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27; as bean name and &quot;</span> + aliases + <span class="string">&quot; as aliases&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (containingBean == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="built_in">this</span>.checkNameUniqueness(beanName, aliases, ele);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">AbstractBeanDefinition</span> <span class="variable">beanDefinition</span> <span class="operator">=</span> <span class="built_in">this</span>.parseBeanDefinitionElement(ele, beanName, containingBean);</span><br><span class="line">    <span class="keyword">if</span> (beanDefinition != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!StringUtils.hasText(beanName)) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (containingBean != <span class="literal">null</span>) &#123;</span><br><span class="line">                    beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, <span class="built_in">this</span>.readerContext.getRegistry(), <span class="literal">true</span>);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    beanName = <span class="built_in">this</span>.readerContext.generateBeanName(beanDefinition);</span><br><span class="line">                    <span class="type">String</span> <span class="variable">beanClassName</span> <span class="operator">=</span> beanDefinition.getBeanClassName();</span><br><span class="line">                    <span class="keyword">if</span> (beanClassName != <span class="literal">null</span> &amp;&amp; beanName.startsWith(beanClassName) &amp;&amp; beanName.length() &gt; beanClassName.length() &amp;&amp; !<span class="built_in">this</span>.readerContext.getRegistry().isBeanNameInUse(beanClassName)) &#123;</span><br><span class="line">                        aliases.add(beanClassName);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.logger.trace(<span class="string">&quot;Neither XML &#x27;id&#x27; nor &#x27;name&#x27; specified - using generated bean name [&quot;</span> + beanName + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception var9) &#123;</span><br><span class="line">                <span class="built_in">this</span>.error(var9.getMessage(), ele);</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        String[] aliasesArray = StringUtils.toStringArray(aliases);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionHolder</span>(beanDefinition, beanName, aliasesArray);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.parseBeanDefinitionElement(ele, beanName, containingBean)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Nullable</span></span><br><span class="line"><span class="keyword">public</span> AbstractBeanDefinition <span class="title function_">parseBeanDefinitionElement</span><span class="params">(Element ele, String beanName, <span class="meta">@Nullable</span> BeanDefinition containingBean)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.parseState.push(<span class="keyword">new</span> <span class="title class_">BeanEntry</span>(beanName));</span><br><span class="line">    <span class="type">String</span> <span class="variable">className</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="comment">//获取className，也就是类的全限定名，例如&quot;com.itheima.a02.A02.Bean1&quot;</span></span><br><span class="line">    <span class="keyword">if</span> (ele.hasAttribute(<span class="string">&quot;class&quot;</span>)) &#123;</span><br><span class="line">        className = ele.getAttribute(<span class="string">&quot;class&quot;</span>).trim();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">String</span> <span class="variable">parent</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (ele.hasAttribute(<span class="string">&quot;parent&quot;</span>)) &#123;</span><br><span class="line">        parent = ele.getAttribute(<span class="string">&quot;parent&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">AbstractBeanDefinition</span> <span class="variable">bd</span> <span class="operator">=</span> <span class="built_in">this</span>.createBeanDefinition(className, parent);</span><br><span class="line">        <span class="comment">// 解析标签上的各种属性，如singleton、abstract、lazy-init等...</span></span><br><span class="line">        <span class="built_in">this</span>.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);</span><br><span class="line">        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, <span class="string">&quot;description&quot;</span>));</span><br><span class="line">        <span class="comment">// 这里解析子元素，例如ConstructorArg、Property等...</span></span><br><span class="line">        <span class="built_in">this</span>.parseMetaElements(ele, bd);</span><br><span class="line">        <span class="built_in">this</span>.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());</span><br><span class="line">        <span class="built_in">this</span>.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());</span><br><span class="line">        <span class="built_in">this</span>.parseConstructorArgElements(ele, bd);</span><br><span class="line">        <span class="built_in">this</span>.parsePropertyElements(ele, bd);</span><br><span class="line">        <span class="built_in">this</span>.parseQualifierElements(ele, bd);</span><br><span class="line">        bd.setResource(<span class="built_in">this</span>.readerContext.getResource());</span><br><span class="line">        bd.setSource(<span class="built_in">this</span>.extractSource(ele));</span><br><span class="line">        <span class="type">AbstractBeanDefinition</span> <span class="variable">var7</span> <span class="operator">=</span> bd;</span><br><span class="line">        <span class="comment">//最后返回AbstractBeanDefinition </span></span><br><span class="line">        <span class="keyword">return</span> var7;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException var13) &#123;</span><br><span class="line">        <span class="built_in">this</span>.error(<span class="string">&quot;Bean class [&quot;</span> + className + <span class="string">&quot;] not found&quot;</span>, ele, var13);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (NoClassDefFoundError var14) &#123;</span><br><span class="line">        <span class="built_in">this</span>.error(<span class="string">&quot;Class that bean class [&quot;</span> + className + <span class="string">&quot;] depends on not found&quot;</span>, ele, var14);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var15) &#123;</span><br><span class="line">        <span class="built_in">this</span>.error(<span class="string">&quot;Unexpected failure during bean definition parsing&quot;</span>, ele, var15);</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.parseState.pop();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个方法解析了<code>bean</code>标签，包括标签上的属性，以及子标签，最后返回了一个<code>AbstractBeanDefinition</code>。</p>
<p>回到<code>DefaultBeanDefinitionDocumentReader</code>类中的<code>processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">processBeanDefinition</span><span class="params">(Element ele, BeanDefinitionParserDelegate delegate)</span> &#123;</span><br><span class="line">    <span class="type">BeanDefinitionHolder</span> <span class="variable">bdHolder</span> <span class="operator">=</span> delegate.parseBeanDefinitionElement(ele);</span><br><span class="line">    <span class="keyword">if</span> (bdHolder != <span class="literal">null</span>) &#123;</span><br><span class="line">        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, <span class="built_in">this</span>.getReaderContext().getRegistry());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (BeanDefinitionStoreException var5) &#123;</span><br><span class="line">            <span class="built_in">this</span>.getReaderContext().error(<span class="string">&quot;Failed to register bean definition with name &#x27;&quot;</span> + bdHolder.getBeanName() + <span class="string">&quot;&#x27;&quot;</span>, ele, var5);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">this</span>.getReaderContext().fireComponentRegistered(<span class="keyword">new</span> <span class="title class_">BeanComponentDefinition</span>(bdHolder));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry())</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">registerBeanDefinition</span><span class="params">(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">beanName</span> <span class="operator">=</span> definitionHolder.getBeanName();</span><br><span class="line">    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());</span><br><span class="line">    String[] aliases = definitionHolder.getAliases();</span><br><span class="line">    <span class="keyword">if</span> (aliases != <span class="literal">null</span>) &#123;</span><br><span class="line">        String[] var4 = aliases;</span><br><span class="line">        <span class="type">int</span> <span class="variable">var5</span> <span class="operator">=</span> aliases.length;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">var6</span> <span class="operator">=</span> <span class="number">0</span>; var6 &lt; var5; ++var6) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">alias</span> <span class="operator">=</span> var4[var6];</span><br><span class="line">            registry.registerAlias(beanName, alias);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">registerBeanDefinition</span><span class="params">(String beanName, BeanDefinition beanDefinition)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    Assert.hasText(beanName, <span class="string">&quot;Bean name must not be empty&quot;</span>);</span><br><span class="line">    Assert.notNull(beanDefinition, <span class="string">&quot;BeanDefinition must not be null&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (beanDefinition <span class="keyword">instanceof</span> AbstractBeanDefinition) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            ((AbstractBeanDefinition)beanDefinition).validate();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (BeanDefinitionValidationException var8) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(beanDefinition.getResourceDescription(), beanName, <span class="string">&quot;Validation of bean definition failed&quot;</span>, var8);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">BeanDefinition</span> <span class="variable">existingDefinition</span> <span class="operator">=</span> (BeanDefinition)<span class="built_in">this</span>.beanDefinitionMap.get(beanName);</span><br><span class="line">    <span class="keyword">if</span> (existingDefinition != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">this</span>.isAllowBeanDefinitionOverriding()) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionOverrideException</span>(beanName, beanDefinition, existingDefinition);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (existingDefinition.getRole() &lt; beanDefinition.getRole()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isInfoEnabled()) &#123;</span><br><span class="line">                <span class="built_in">this</span>.logger.info(<span class="string">&quot;Overriding user-defined bean definition for bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27; with a framework-generated bean definition: replacing [&quot;</span> + existingDefinition + <span class="string">&quot;] with [&quot;</span> + beanDefinition + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!beanDefinition.equals(existingDefinition)) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isDebugEnabled()) &#123;</span><br><span class="line">                <span class="built_in">this</span>.logger.debug(<span class="string">&quot;Overriding bean definition for bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27; with a different definition: replacing [&quot;</span> + existingDefinition + <span class="string">&quot;] with [&quot;</span> + beanDefinition + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">            <span class="built_in">this</span>.logger.trace(<span class="string">&quot;Overriding bean definition for bean &#x27;&quot;</span> + beanName + <span class="string">&quot;&#x27; with an equivalent definition: replacing [&quot;</span> + existingDefinition + <span class="string">&quot;] with [&quot;</span> + beanDefinition + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">this</span>.beanDefinitionMap.put(beanName, beanDefinition);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.hasBeanCreationStarted()) &#123;</span><br><span class="line">            <span class="keyword">synchronized</span>(<span class="built_in">this</span>.beanDefinitionMap) &#123;</span><br><span class="line">                <span class="built_in">this</span>.beanDefinitionMap.put(beanName, beanDefinition);</span><br><span class="line">                List&lt;String&gt; updatedDefinitions = <span class="keyword">new</span> <span class="title class_">ArrayList</span>(<span class="built_in">this</span>.beanDefinitionNames.size() + <span class="number">1</span>);</span><br><span class="line">                updatedDefinitions.addAll(<span class="built_in">this</span>.beanDefinitionNames);</span><br><span class="line">                updatedDefinitions.add(beanName);</span><br><span class="line">                <span class="built_in">this</span>.beanDefinitionNames = updatedDefinitions;</span><br><span class="line">                <span class="built_in">this</span>.removeManualSingletonName(beanName);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//将beanName与beanDefinition的映射放入beanDefinitionMap，beanDefinition中包含了类的全限定名称</span></span><br><span class="line">            <span class="built_in">this</span>.beanDefinitionMap.put(beanName, beanDefinition);</span><br><span class="line">            <span class="built_in">this</span>.beanDefinitionNames.add(beanName);</span><br><span class="line">            <span class="built_in">this</span>.removeManualSingletonName(beanName);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">this</span>.frozenBeanDefinitionNames = <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (existingDefinition == <span class="literal">null</span> &amp;&amp; !<span class="built_in">this</span>.containsSingleton(beanName)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.isConfigurationFrozen()) &#123;</span><br><span class="line">            <span class="built_in">this</span>.clearByTypeCache();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.resetBeanDefinition(beanName);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>注意这两行代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.beanDefinitionMap.put(beanName, beanDefinition);</span><br><span class="line"><span class="built_in">this</span>.beanDefinitionNames.add(beanName);</span><br></pre></td></tr></table></figure>

<p>就是将<code>beanName</code>与<code>beanDefinition</code>的映射放入<code>beanDefinitionMap</code>中，<code>beanName</code>放入<code>beanDefinitionNames</code>中，我们可以在<code>DefaultListableBeanFactory</code>类中通过这两个容器拿到对应属性。</p>
<ol start="2">
<li>FileSystemXmlApplicationContext</li>
</ol>
<p><strong>使用演示</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">    <span class="comment">// ⬇️基于磁盘路径下 xml 格式的配置文件来创建</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testFileSystemXmlApplicationContext</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 基于文件绝对路径</span></span><br><span class="line"><span class="comment">//        FileSystemXmlApplicationContext context =</span></span><br><span class="line"><span class="comment">//                new FileSystemXmlApplicationContext(</span></span><br><span class="line"><span class="comment">//                        &quot;c:\\Users\\manyh\\Desktop\\demo\\show\\src\\main\\resources\\a02.xml&quot;);</span></span><br><span class="line">        <span class="comment">// 基于项目相对路径</span></span><br><span class="line">        <span class="type">FileSystemXmlApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">FileSystemXmlApplicationContext</span>(</span><br><span class="line">                        <span class="string">&quot;src\\main\\resources\\a02.xml&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(context.getBean(Bean2.class).getBean1());</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：使用相对路径时我们要指定工作目录为当前模块(默认为当前项目)：</p>
</blockquote>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/7.png" alt="img"></p>
<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bean1</span><br><span class="line">bean2</span><br><span class="line">com.itheima.a02.A02$Bean1@1de5f259</span><br></pre></td></tr></table></figure>

<p>我们发现Bean已经成功地被注入。</p>
<p><strong>源码剖析</strong></p>
<p>大致步骤和<code>ClassPathXmlApplicationContext</code>加载配置文件过程类似，不同的是在<code>AbstractXmlApplicationContext</code>中的<code>loadBeanDefinitions(DefaultListableBeanFactory beanFactory)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(DefaultListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> BeansException, IOException &#123;</span><br><span class="line">    <span class="type">XmlBeanDefinitionReader</span> <span class="variable">beanDefinitionReader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">XmlBeanDefinitionReader</span>(beanFactory);</span><br><span class="line">    beanDefinitionReader.setEnvironment(<span class="built_in">this</span>.getEnvironment());</span><br><span class="line">    beanDefinitionReader.setResourceLoader(<span class="built_in">this</span>);</span><br><span class="line">    beanDefinitionReader.setEntityResolver(<span class="keyword">new</span> <span class="title class_">ResourceEntityResolver</span>(<span class="built_in">this</span>));</span><br><span class="line">    <span class="built_in">this</span>.initBeanDefinitionReader(beanDefinitionReader);</span><br><span class="line">    <span class="built_in">this</span>.loadBeanDefinitions(beanDefinitionReader);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在<code>beanDefinitionReader.setResourceLoader(this)</code>时，使用<code>ClassPathXmlApplicationContext</code>则代表<code>ClassPathXmlApplicationContext</code>实例，使用<code>FileSystemXmlApplicationContext</code>时则代表<code>FileSystemXmlApplicationContext</code>实例。</p>
<p>进入<code>this.loadBeanDefinitions(beanDefinitionReader)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(XmlBeanDefinitionReader reader)</span> <span class="keyword">throws</span> BeansException, IOException &#123;</span><br><span class="line">    Resource[] configResources = <span class="built_in">this</span>.getConfigResources();</span><br><span class="line">    <span class="keyword">if</span> (configResources != <span class="literal">null</span>) &#123;</span><br><span class="line">        reader.loadBeanDefinitions(configResources);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    String[] configLocations = <span class="built_in">this</span>.getConfigLocations();</span><br><span class="line">    <span class="keyword">if</span> (configLocations != <span class="literal">null</span>) &#123;</span><br><span class="line">        reader.loadBeanDefinitions(configLocations);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再进入<code>reader.loadBeanDefinitions(configLocations)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(String... locations)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    Assert.notNull(locations, <span class="string">&quot;Location array must not be null&quot;</span>);</span><br><span class="line">    <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">    String[] var3 = locations;</span><br><span class="line">    <span class="type">int</span> <span class="variable">var4</span> <span class="operator">=</span> locations.length;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">var5</span> <span class="operator">=</span> <span class="number">0</span>; var5 &lt; var4; ++var5) &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">location</span> <span class="operator">=</span> var3[var5];</span><br><span class="line">        count += <span class="built_in">this</span>.loadBeanDefinitions(location);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再进入<code>this.loadBeanDefinitions(location)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(String location)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.loadBeanDefinitions(location, (Set)<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>再进入<code>this.loadBeanDefinitions(location, (Set)null)</code>方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">loadBeanDefinitions</span><span class="params">(String location, <span class="meta">@Nullable</span> Set&lt;Resource&gt; actualResources)</span> <span class="keyword">throws</span> BeanDefinitionStoreException &#123;</span><br><span class="line">    <span class="comment">// 首先获取ResourceLoader</span></span><br><span class="line">    <span class="type">ResourceLoader</span> <span class="variable">resourceLoader</span> <span class="operator">=</span> <span class="built_in">this</span>.getResourceLoader();</span><br><span class="line">    <span class="keyword">if</span> (resourceLoader == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(<span class="string">&quot;Cannot load bean definitions from location [&quot;</span> + location + <span class="string">&quot;]: no ResourceLoader available&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="type">int</span> count;</span><br><span class="line">        <span class="comment">// 判断是否实现了ResourcePatternResolver</span></span><br><span class="line">        <span class="keyword">if</span> (resourceLoader <span class="keyword">instanceof</span> ResourcePatternResolver) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 根据ResourceLoader的getResources()方法获取resources</span></span><br><span class="line">                Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);</span><br><span class="line">                count = <span class="built_in">this</span>.loadBeanDefinitions(resources);</span><br><span class="line">                <span class="keyword">if</span> (actualResources != <span class="literal">null</span>) &#123;</span><br><span class="line">                    Collections.addAll(actualResources, resources);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">this</span>.logger.isTraceEnabled()) &#123;</span><br><span class="line">                    <span class="built_in">this</span>.logger.trace(<span class="string">&quot;Loaded &quot;</span> + count + <span class="string">&quot; bean definitions from location pattern [&quot;</span> + location + <span class="string">&quot;]&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> count;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException var6) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanDefinitionStoreException</span>(<span class="string">&quot;Could not resolve bean definition resource pattern [&quot;</span> + location + <span class="string">&quot;]&quot;</span>, var6);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="comment">//...</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>ClassPathXmlApplicationContext</code>和<code>FileSystemXmlApplicationContext</code>既实现了<code>ResourceLoader</code>接口，又实现了<code>ResourcePatternResolver</code>接口</p>
<p><code>ClassPathXmlApplicationContext</code>的类结构图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/8.png" alt="img"></p>
<p><code>FileSystemXmlApplicationContext</code>的类结构图：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/9.png" alt="img"></p>
<p><code>ClassPathXmlApplicationContext</code>和<code>FileSystemXmlApplicationContext</code>的间接父类<code>AbstractApplicationContext</code>实现了<code>getResources(location)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Resource[] getResources(String locationPattern) <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.resourcePatternResolver.getResources(locationPattern);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>进入<code>this.resourcePatternResolver.getResources(locationPattern)</code>方法(实际上进入的时<code>PathMatchingResourcePatternResolver</code>方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Resource[] getResources(String locationPattern) <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    Assert.notNull(locationPattern, <span class="string">&quot;Location pattern must not be null&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (locationPattern.startsWith(<span class="string">&quot;classpath*:&quot;</span>)) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getPathMatcher().isPattern(locationPattern.substring(<span class="string">&quot;classpath*:&quot;</span>.length())) ? <span class="built_in">this</span>.findPathMatchingResources(locationPattern) : <span class="built_in">this</span>.findAllClassPathResources(locationPattern.substring(<span class="string">&quot;classpath*:&quot;</span>.length()));</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">prefixEnd</span> <span class="operator">=</span> locationPattern.startsWith(<span class="string">&quot;war:&quot;</span>) ? locationPattern.indexOf(<span class="string">&quot;*/&quot;</span>) + <span class="number">1</span> : locationPattern.indexOf(<span class="number">58</span>) + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.getPathMatcher().isPattern(locationPattern.substring(prefixEnd)) ? <span class="built_in">this</span>.findPathMatchingResources(locationPattern) : <span class="keyword">new</span> <span class="title class_">Resource</span>[]&#123;<span class="built_in">this</span>.getResourceLoader().getResource(locationPattern)&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>注意<code>this.getResourceLoader().getResource(locationPattern)</code>，会调用<code>DefaultResourceLoader</code>类的<code>getResource(locationPattern)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Resource <span class="title function_">getResource</span><span class="params">(String location)</span> &#123;</span><br><span class="line">    Assert.notNull(location, <span class="string">&quot;Location must not be null&quot;</span>);</span><br><span class="line">    <span class="type">Iterator</span> <span class="variable">var2</span> <span class="operator">=</span> <span class="built_in">this</span>.getProtocolResolvers().iterator();</span><br><span class="line"></span><br><span class="line">    Resource resource;</span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!var2.hasNext()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (location.startsWith(<span class="string">&quot;/&quot;</span>)) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="built_in">this</span>.getResourceByPath(location);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (location.startsWith(<span class="string">&quot;classpath:&quot;</span>)) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ClassPathResource</span>(location.substring(<span class="string">&quot;classpath:&quot;</span>.length()), <span class="built_in">this</span>.getClassLoader());</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="type">URL</span> <span class="variable">url</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">URL</span>(location);</span><br><span class="line">                <span class="keyword">return</span> (Resource)(ResourceUtils.isFileURL(url) ? <span class="keyword">new</span> <span class="title class_">FileUrlResource</span>(url) : <span class="keyword">new</span> <span class="title class_">UrlResource</span>(url));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (MalformedURLException var5) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="built_in">this</span>.getResourceByPath(location);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">ProtocolResolver</span> <span class="variable">protocolResolver</span> <span class="operator">=</span> (ProtocolResolver)var2.next();</span><br><span class="line">        resource = protocolResolver.resolve(location, <span class="built_in">this</span>);</span><br><span class="line">    &#125; <span class="keyword">while</span>(resource == <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> resource;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>ClassPathXmlApplicationContext</code>使用的是<code>DefaultResourceLoader</code>类的<code>getResourceByPath(location)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> Resource <span class="title function_">getResourceByPath</span><span class="params">(String path)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ClassPathContextResource</span>(path, <span class="built_in">this</span>.getClassLoader());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">ClassPathContextResource</span> <span class="keyword">extends</span> <span class="title class_">ClassPathResource</span> <span class="keyword">implements</span> <span class="title class_">ContextResource</span> &#123;</span><br><span class="line">    <span class="comment">// 调用此构造方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ClassPathContextResource</span><span class="params">(String path, <span class="meta">@Nullable</span> ClassLoader classLoader)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(path, classLoader);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ClassPathResource</span> <span class="keyword">extends</span> <span class="title class_">AbstractFileResolvingResource</span> &#123;</span><br><span class="line">    <span class="comment">// 调用此构造方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ClassPathResource</span><span class="params">(String path, <span class="meta">@Nullable</span> ClassLoader classLoader)</span> &#123;</span><br><span class="line">        Assert.notNull(path, <span class="string">&quot;Path must not be null&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">pathToUse</span> <span class="operator">=</span> StringUtils.cleanPath(path);</span><br><span class="line">        <span class="keyword">if</span> (pathToUse.startsWith(<span class="string">&quot;/&quot;</span>)) &#123;</span><br><span class="line">            pathToUse = pathToUse.substring(<span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">        <span class="built_in">this</span>.path = pathToUse;</span><br><span class="line">        <span class="built_in">this</span>.classLoader = classLoader != <span class="literal">null</span> ? classLoader : ClassUtils.getDefaultClassLoader();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>而<code>FileSystemXmlApplicationContext</code>重写了<code>getResourceByPath(location)</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> Resource <span class="title function_">getResourceByPath</span><span class="params">(String path)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (path.startsWith(<span class="string">&quot;/&quot;</span>)) &#123;</span><br><span class="line">        path = path.substring(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">FileSystemResource</span>(path);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FileSystemResource</span> <span class="keyword">extends</span> <span class="title class_">AbstractResource</span> <span class="keyword">implements</span> <span class="title class_">WritableResource</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String path;</span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> File file;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Path filePath;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 调用此构造方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">FileSystemResource</span><span class="params">(String path)</span> &#123;</span><br><span class="line">        Assert.notNull(path, <span class="string">&quot;Path must not be null&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.path = StringUtils.cleanPath(path);</span><br><span class="line">        <span class="built_in">this</span>.file = <span class="keyword">new</span> <span class="title class_">File</span>(path);</span><br><span class="line">        <span class="built_in">this</span>.filePath = <span class="built_in">this</span>.file.toPath();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>ClassPathXmlApplicationContext</code>与<code>FileSystemXmlApplicationContext</code>返回的是不同的<code>Resource </code>。</p>
<ol start="3">
<li>AnnotationConfigApplicationContext</li>
</ol>
<p><strong>使用演示</strong></p>
<p>准备配置类，并加上注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> Bean1 <span class="title function_">bean1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> Bean2 <span class="title function_">bean2</span><span class="params">(Bean1 bean1)</span> &#123;</span><br><span class="line">        <span class="type">Bean2</span> <span class="variable">bean2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Bean2</span>();</span><br><span class="line">        bean2.setBean1(bean1);</span><br><span class="line">        <span class="keyword">return</span> bean2;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ⬇️较为经典的容器, 基于 java 配置类来创建</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">testAnnotationConfigApplicationContext</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span></span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(Config.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">        System.out.println(name);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    System.out.println(context.getBean(Bean2.class).getBean1());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br><span class="line">a02.Config</span><br><span class="line">bean1</span><br><span class="line">bean2</span><br><span class="line">com.itheima.a02.A02$Bean1@12591ac8</span><br></pre></td></tr></table></figure>

<p>我们发现除了注入了添加了注解的Bean，还注入了一些后处理器，这是由Spring主动给我们注入的。</p>
<p>配置xml的时候也可以通过标签去加入这些后处理器：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">context:annotation-config</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p><strong>源码剖析</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">//todo</span><br></pre></td></tr></table></figure>

<ol start="4">
<li>AnnotationConfigServletWebServerApplicationContext</li>
</ol>
<p><strong>使用演示</strong></p>
<p>准备配置类，并加上注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">WebConfig</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> ServletWebServerFactory <span class="title function_">servletWebServerFactory</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="comment">// 创建tomacat容器</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">TomcatServletWebServerFactory</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> DispatcherServlet <span class="title function_">dispatcherServlet</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 创建DispatcherServlet</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DispatcherServlet</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> DispatcherServletRegistrationBean <span class="title function_">registrationBean</span><span class="params">(DispatcherServlet dispatcherServlet)</span> &#123;</span><br><span class="line">        <span class="comment">// 注册DispatcherServletRegistrationBean，绑定拦截路径</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DispatcherServletRegistrationBean</span>(dispatcherServlet, <span class="string">&quot;/&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Bean(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Controller <span class="title function_">controller1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 创建一个Controller </span></span><br><span class="line">        <span class="keyword">return</span> (request, response) -&gt; &#123;</span><br><span class="line">            response.getWriter().print(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">[INFO ] 15:18:51.535 [main] o.s.b.w.e.tomcat.TomcatWebServer    - Tomcat initialized with port(s): 8080 (http) </span><br><span class="line">3�� 26, 2023 3:18:51 ���� org.apache.coyote.AbstractProtocol init</span><br><span class="line">��Ϣ: Initializing ProtocolHandler [&quot;http-nio-8080&quot;]</span><br><span class="line">3�� 26, 2023 3:18:51 ���� org.apache.catalina.core.StandardService startInternal</span><br><span class="line">��Ϣ: Starting service [Tomcat]</span><br><span class="line">3�� 26, 2023 3:18:51 ���� org.apache.catalina.core.StandardEngine startInternal</span><br><span class="line">��Ϣ: Starting Servlet engine: [Apache Tomcat/9.0.53]</span><br><span class="line">3�� 26, 2023 3:18:51 ���� org.apache.catalina.core.ApplicationContext log</span><br><span class="line">��Ϣ: Initializing Spring embedded WebApplicationContext</span><br><span class="line">[INFO ] 15:18:51.682 [main] o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 814 ms </span><br><span class="line">3�� 26, 2023 3:18:51 ���� org.apache.coyote.AbstractProtocol start</span><br><span class="line">��Ϣ: Starting ProtocolHandler [&quot;http-nio-8080&quot;]</span><br><span class="line">[INFO ] 15:18:51.804 [main] o.s.b.w.e.tomcat.TomcatWebServer    - Tomcat started on port(s): 8080 (http) with context path &#x27;&#x27; </span><br><span class="line">org.springframework.context.annotation.internalConfigurationAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalAutowiredAnnotationProcessor</span><br><span class="line">org.springframework.context.annotation.internalCommonAnnotationProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerProcessor</span><br><span class="line">org.springframework.context.event.internalEventListenerFactory</span><br><span class="line">a02.WebConfig</span><br><span class="line">servletWebServerFactory</span><br><span class="line">dispatcherServlet</span><br><span class="line">registrationBean</span><br><span class="line">/hello</span><br></pre></td></tr></table></figure>

<p>我们发现tomcat也打印了很多日志，监听了8080端口，尝试访问localhost:8080&#x2F;hello，浏览器返回：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hello</span><br></pre></td></tr></table></figure>

<p>说明生效了。</p>
<p><strong>源码剖析</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">//todo</span><br></pre></td></tr></table></figure>

<h1 id="Bean的生命周期"><a href="#Bean的生命周期" class="headerlink" title="Bean的生命周期"></a>Bean的生命周期</h1><h2 id="Bean的生命周期-1"><a href="#Bean的生命周期-1" class="headerlink" title="Bean的生命周期"></a>Bean的生命周期</h2><p>准备<code>Component</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LifeCycleBean</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(LifeCycleBean.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">LifeCycleBean</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;构造&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">autowire</span><span class="params">(<span class="meta">@Value(&quot;$&#123;JAVA_HOME&#125;&quot;)</span> String home)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;依赖注入: &#123;&#125;&quot;</span>, home);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;初始化&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;销毁&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A03</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> SpringApplication.run(A03.class, args);</span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">//...</span><br><span class="line">[DEBUG] 15:30:04.169 [main] com.itheima.a03.LifeCycleBean       - 构造 </span><br><span class="line">[DEBUG] 15:30:04.172 [main] com.itheima.a03.LifeCycleBean       - 依赖注入: C:\Path\jdk-14.0.1 </span><br><span class="line">[DEBUG] 15:30:04.173 [main] com.itheima.a03.LifeCycleBean       - 初始化 </span><br><span class="line">//...</span><br><span class="line">[DEBUG] 15:30:04.755 [main] com.itheima.a03.LifeCycleBean       - 销毁 </span><br></pre></td></tr></table></figure>

<p>发现执行顺序是(即<code>Bean</code>生命周期的四个阶段)：</p>
<ol>
<li>构造方法</li>
<li><code>@Autowired</code>依赖注入</li>
<li><code>@PostConstruct</code>初始化</li>
<li><code>@PreDestroy</code>销毁</li>
</ol>
<p><code>Spring</code>的<code>BeanFactory</code>默认只有一些核心功能，扩展功能是通过后处理器来实现的。有<code>BeanFacotry</code>后处理器与<code>Bean</code>后处理器。<code>BeanFactory</code>后处理器主要补充<code>BeanFactory</code>的一些定义，<code>Bean</code>后处理器主要提供<code>Bean</code>的生命周期各个阶段的扩展。</p>
<p>这里主要演示<code>Bean</code>后处理器的使用：</p>
<blockquote>
<p><code>InstantiationAwareBeanPostProcessor</code>类和<code>DestructionAwareBeanPostProcessor</code>类都继承了<code>BeanPostProcessor</code>接口</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyBeanPostProcessor</span> <span class="keyword">implements</span> <span class="title class_">InstantiationAwareBeanPostProcessor</span>, DestructionAwareBeanPostProcessor &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyBeanPostProcessor.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeforeDestruction</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;lifeCycleBean&quot;</span>))</span><br><span class="line">            log.debug(<span class="string">&quot;&lt;&lt;&lt;&lt;&lt;&lt; 销毁之前执行, 如 @PreDestroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessBeforeInstantiation</span><span class="params">(Class&lt;?&gt; beanClass, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;lifeCycleBean&quot;</span>))</span><br><span class="line">            log.debug(<span class="string">&quot;&lt;&lt;&lt;&lt;&lt;&lt; 实例化之前执行, 这里返回的对象会替换掉原本的 bean&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">postProcessAfterInstantiation</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;lifeCycleBean&quot;</span>)) &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;&lt;&lt;&lt;&lt;&lt;&lt; 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段&quot;</span>);</span><br><span class="line"><span class="comment">//            return false;</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> PropertyValues <span class="title function_">postProcessProperties</span><span class="params">(PropertyValues pvs, Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;lifeCycleBean&quot;</span>))</span><br><span class="line">            log.debug(<span class="string">&quot;&lt;&lt;&lt;&lt;&lt;&lt; 依赖注入阶段执行, 如 @Autowired、@Value、@Resource&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> pvs;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessBeforeInitialization</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;lifeCycleBean&quot;</span>))</span><br><span class="line">            log.debug(<span class="string">&quot;&lt;&lt;&lt;&lt;&lt;&lt; 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessAfterInitialization</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (beanName.equals(<span class="string">&quot;lifeCycleBean&quot;</span>))</span><br><span class="line">            log.debug(<span class="string">&quot;&lt;&lt;&lt;&lt;&lt;&lt; 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 15:42:57.321 [main] com.itheima.a03.MyBeanPostProcessor - &lt;&lt;&lt;&lt;&lt;&lt; 实例化之前执行, 这里返回的对象会替换掉原本的 bean </span><br><span class="line">[DEBUG] 15:42:57.323 [main] com.itheima.a03.LifeCycleBean       - 构造 </span><br><span class="line">[DEBUG] 15:42:57.325 [main] com.itheima.a03.MyBeanPostProcessor - &lt;&lt;&lt;&lt;&lt;&lt; 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段 </span><br><span class="line">[DEBUG] 15:42:57.325 [main] com.itheima.a03.MyBeanPostProcessor - &lt;&lt;&lt;&lt;&lt;&lt; 依赖注入阶段执行, 如 @Autowired、@Value、@Resource </span><br><span class="line">[DEBUG] 15:42:57.326 [main] com.itheima.a03.LifeCycleBean       - 依赖注入: C:\Path\jdk-14.0.1 </span><br><span class="line">[DEBUG] 15:42:57.328 [main] com.itheima.a03.MyBeanPostProcessor - &lt;&lt;&lt;&lt;&lt;&lt; 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties </span><br><span class="line">[DEBUG] 15:42:57.328 [main] com.itheima.a03.LifeCycleBean       - 初始化 </span><br><span class="line">[DEBUG] 15:42:57.328 [main] com.itheima.a03.MyBeanPostProcessor - &lt;&lt;&lt;&lt;&lt;&lt; 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强 </span><br><span class="line">//...</span><br><span class="line">[DEBUG] 15:42:57.972 [main] com.itheima.a03.MyBeanPostProcessor - &lt;&lt;&lt;&lt;&lt;&lt; 销毁之前执行, 如 @PreDestroy </span><br><span class="line">[DEBUG] 15:42:57.973 [main] com.itheima.a03.LifeCycleBean       - 销毁 </span><br></pre></td></tr></table></figure>

<p>可以观察到功能增强方法调用的各个时机。</p>
<h2 id="模板方法模式"><a href="#模板方法模式" class="headerlink" title="模板方法模式"></a>模板方法模式</h2><p>准备类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestMethodTemplate</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 模板方法  Template Method Pattern</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyBeanFactory</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">getBean</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">            System.out.println(<span class="string">&quot;构造 &quot;</span> + bean);</span><br><span class="line">            System.out.println(<span class="string">&quot;依赖注入 &quot;</span> + bean);</span><br><span class="line">            System.out.println(<span class="string">&quot;初始化 &quot;</span> + bean);</span><br><span class="line">            <span class="keyword">return</span> bean;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上类，如果我们想要增加<code>getBean()</code>方法的功能，我们必须要更改<code>getBean()</code>方法的代码，会使得<code>getBean()</code>方法越来越臃肿。</p>
<p>因此，我们可以在代码中织入可能增强的操作：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestMethodTemplate</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">MyBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyBeanFactory</span>();</span><br><span class="line">        beanFactory.addBeanPostProcessor(bean -&gt; System.out.println(<span class="string">&quot;解析 @Autowired&quot;</span>));</span><br><span class="line">        beanFactory.addBeanPostProcessor(bean -&gt; System.out.println(<span class="string">&quot;解析 @Resource&quot;</span>));</span><br><span class="line">        beanFactory.getBean();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 模板方法  Template Method Pattern</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyBeanFactory</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">getBean</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="type">Object</span> <span class="variable">bean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">            System.out.println(<span class="string">&quot;构造 &quot;</span> + bean);</span><br><span class="line">            System.out.println(<span class="string">&quot;依赖注入 &quot;</span> + bean); <span class="comment">// @Autowired, @Resource</span></span><br><span class="line">            <span class="keyword">for</span> (BeanPostProcessor processor : processors) &#123;</span><br><span class="line">                processor.inject(bean);</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;初始化 &quot;</span> + bean);</span><br><span class="line">            <span class="keyword">return</span> bean;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> List&lt;BeanPostProcessor&gt; processors = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">addBeanPostProcessor</span><span class="params">(BeanPostProcessor processor)</span> &#123;</span><br><span class="line">            processors.add(processor);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">interface</span> <span class="title class_">BeanPostProcessor</span> &#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">inject</span><span class="params">(Object bean)</span>; <span class="comment">// 对依赖注入阶段的扩展</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>不变的代码是模板，可变的就是增强的功能，这就是模板方法模式。</p>
<h1 id="Bean后处理器"><a href="#Bean后处理器" class="headerlink" title="Bean后处理器"></a>Bean后处理器</h1><h2 id="常见的Bean后处理器"><a href="#常见的Bean后处理器" class="headerlink" title="常见的Bean后处理器"></a>常见的Bean后处理器</h2><p>这里介绍常见的三个Bean后处理器：</p>
<ul>
<li><code>AutowiredAnnotationBeanPostProcessor</code>：主要用来解析<code>@Autowired</code>、<code>@Value</code>等注解。</li>
<li><code>CommonAnnotationBeanPostProcessor</code>：主要用来解析<code>@Resource</code>、<code>@PostConstruct</code>、<code>@PreDestroy</code>等注解。</li>
<li><code>ConfigurationPropertiesBindingPostProcessor</code>：主要提供属性绑定的功能。</li>
</ul>
<p>准备类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Bean2 bean2;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean2</span><span class="params">(Bean2 bean2)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;@Autowired 生效: &#123;&#125;&quot;</span>, bean2);</span><br><span class="line">        <span class="built_in">this</span>.bean2 = bean2;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Bean3 bean3;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBean3</span><span class="params">(Bean3 bean3)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;@Resource 生效: &#123;&#125;&quot;</span>, bean3);</span><br><span class="line">        <span class="built_in">this</span>.bean3 = bean3;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String home;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setHome</span><span class="params">(<span class="meta">@Value(&quot;$&#123;JAVA_HOME&#125;&quot;)</span> String home)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;@Value 生效: &#123;&#125;&quot;</span>, home);</span><br><span class="line">        <span class="built_in">this</span>.home = home;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;@PostConstruct 生效&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;@PreDestroy 生效&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Bean1&#123;&quot;</span> +</span><br><span class="line">               <span class="string">&quot;bean2=&quot;</span> + bean2 +</span><br><span class="line">               <span class="string">&quot;, bean3=&quot;</span> + bean3 +</span><br><span class="line">               <span class="string">&quot;, home=&#x27;&quot;</span> + home + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">               <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean3</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A04</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">// ⬇️GenericApplicationContext 是一个【干净】的容器</span></span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// ⬇️用原始方法注册三个 bean</span></span><br><span class="line">        context.registerBean(<span class="string">&quot;bean1&quot;</span>, Bean1.class);</span><br><span class="line">        context.registerBean(<span class="string">&quot;bean2&quot;</span>, Bean2.class);</span><br><span class="line">        context.registerBean(<span class="string">&quot;bean3&quot;</span>, Bean3.class);</span><br><span class="line"></span><br><span class="line">       </span><br><span class="line">        <span class="comment">// ⬇️初始化容器</span></span><br><span class="line">        context.refresh(); <span class="comment">// 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">// ⬇️销毁容器</span></span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，发现控制台输出为空，说明<code>Bean1</code>中的注解都没有生效。这是因为我们没有添加<code>Bean</code>的后处理器。</p>
<ol>
<li>AutowiredAnnotationBeanPostProcessor</li>
</ol>
<p><code>AutowiredAnnotationBeanPostProcessor</code>主要用来解析<code>@Autowired</code>、<code>@Value</code>等注解。</p>
<p>我们添加以下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 支持值注入</span></span><br><span class="line">context.getDefaultListableBeanFactory().setAutowireCandidateResolver(<span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>());</span><br><span class="line"><span class="comment">// @Autowired @Value</span></span><br><span class="line">context.registerBean(AutowiredAnnotationBeanPostProcessor.class); </span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台，我们发现<code>@Autowired</code>、<code>@Value</code>等注解已经生效：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 17:49:43.017 [main] com.itheima.a04.Bean1               - @Autowired 生效: com.itheima.a04.Bean2@6bf0219d </span><br><span class="line">[DEBUG] 17:49:43.041 [main] com.itheima.a04.Bean1               - @Value 生效: C:\Path\jdk-14.0.1 </span><br></pre></td></tr></table></figure>

<ol start="2">
<li>CommonAnnotationBeanPostProcessor</li>
</ol>
<p><code>CommonAnnotationBeanPostProcessor</code>：主要用来解析<code>@Resource</code>、<code>@PostConstruct</code>、<code>@PreDestroy</code>等注解。</p>
<p>我们添加以下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(CommonAnnotationBeanPostProcessor.class); <span class="comment">// @Resource @PostConstruct @PreDestroy</span></span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台，发现@<code>Resource</code>、<code>@PostConstruct</code>、<code>@PreDestroy</code>等注解已经生效：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 17:53:58.129 [main] com.itheima.a04.Bean1               - @Resource 生效: com.itheima.a04.Bean3@1356d4d4 </span><br><span class="line">[DEBUG] 17:53:58.192 [main] com.itheima.a04.Bean1               - @Autowired 生效: com.itheima.a04.Bean2@3541cb24 </span><br><span class="line">[DEBUG] 17:53:58.225 [main] com.itheima.a04.Bean1               - @Value 生效: C:\Path\jdk-14.0.1 </span><br><span class="line">[DEBUG] 17:53:58.231 [main] com.itheima.a04.Bean1               - @PostConstruct 生效 </span><br><span class="line">[DEBUG] 17:53:58.255 [main] com.itheima.a04.Bean1               - @PreDestroy 生效 </span><br></pre></td></tr></table></figure>

<ol start="3">
<li>ConfigurationPropertiesBindingPostProcessor</li>
</ol>
<p><code>ConfigurationPropertiesBindingPostProcessor</code>主要提供属性绑定的功能。</p>
<p>我们准备以下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;java&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean4</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String home;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String version;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getHome</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> home;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setHome</span><span class="params">(String home)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.home = home;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getVersion</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> version;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setVersion</span><span class="params">(String version)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.version = version;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Bean4&#123;&quot;</span> +</span><br><span class="line">               <span class="string">&quot;home=&#x27;&quot;</span> + home + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">               <span class="string">&quot;, version=&#x27;&quot;</span> + version + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">               <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在main方法中加入：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());</span><br><span class="line"><span class="comment">//...</span></span><br><span class="line">System.out.println(context.getBean(Bean4.class));</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台，发现属性已经绑定到类中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//...</span></span><br><span class="line">Bean4&#123;home=<span class="string">&#x27;C:\Path\jdk-20&#x27;</span>, version=<span class="string">&#x27;20&#x27;</span>&#125;</span><br><span class="line"><span class="comment">//...</span></span><br></pre></td></tr></table></figure>

<h2 id="依赖注解后处理器执行流程"><a href="#依赖注解后处理器执行流程" class="headerlink" title="依赖注解后处理器执行流程"></a>依赖注解后处理器执行流程</h2><p>本节主要对AutowiredAnnotationBeanPostProcessor的执行流程进行分析。</p>
<h3 id="findAutowiringMetadata"><a href="#findAutowiringMetadata" class="headerlink" title="findAutowiringMetadata()"></a>findAutowiringMetadata()</h3><p><code>findAutowiringMetadata()</code>方法主要用来获取需要进行依赖注入的元信息。</p>
<p>首先准备代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DigInAutowired</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultListableBeanFactory</span>();</span><br><span class="line">        <span class="comment">// 创建过程,依赖注入,初始化</span></span><br><span class="line">        beanFactory.registerSingleton(<span class="string">&quot;bean2&quot;</span>, <span class="keyword">new</span> <span class="title class_">Bean2</span>()); </span><br><span class="line">        beanFactory.registerSingleton(<span class="string">&quot;bean3&quot;</span>, <span class="keyword">new</span> <span class="title class_">Bean3</span>());</span><br><span class="line">        beanFactory.setAutowireCandidateResolver(<span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>()); <span class="comment">// @Value解析</span></span><br><span class="line">        beanFactory.addEmbeddedValueResolver(<span class="keyword">new</span> <span class="title class_">StandardEnvironment</span>()::resolvePlaceholders); <span class="comment">// $&#123;&#125; 的解析器</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata</span></span><br><span class="line">        <span class="type">AutowiredAnnotationBeanPostProcessor</span> <span class="variable">processor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AutowiredAnnotationBeanPostProcessor</span>();</span><br><span class="line">        processor.setBeanFactory(beanFactory);</span><br><span class="line">        </span><br><span class="line">        <span class="type">Bean1</span> <span class="variable">bean1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">        System.out.println(bean1);</span><br><span class="line">        processor.postProcessProperties(<span class="literal">null</span>, bean1, <span class="string">&quot;bean1&quot;</span>); <span class="comment">// 执行依赖注入 @Autowired @Value</span></span><br><span class="line">        System.out.println(bean1);</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Bean1&#123;bean2=null, bean3=null, home=&#x27;null&#x27;&#125;</span><br><span class="line">[DEBUG] 18:17:08.121 [main] com.itheima.a04.Bean1               - @Autowired 生效: com.itheima.a04.Bean2@175c2241 </span><br><span class="line">[DEBUG] 18:17:08.135 [main] com.itheima.a04.Bean1               - @Value 生效: C:\Path\jdk-14.0.1 </span><br><span class="line">Bean1&#123;bean2=com.itheima.a04.Bean2@175c2241, bean3=com.itheima.a04.Bean3@6025e1b6, home=&#x27;C:\Path\jdk-14.0.1&#x27;&#125;</span><br></pre></td></tr></table></figure>

<p>我们发现，在<code>processor.postProcessProperties(null, bean1, &quot;bean1&quot;)</code>方法执行之前，Bean1并没有进行依赖注入，而执行之后成功执行了依赖注入。说明<code>postProcessProperties(null, bean1, &quot;bean1&quot;)</code>方法是执行依赖注入的核心方法。</p>
<p>进入<code>postProcessProperties()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> PropertyValues <span class="title function_">postProcessProperties</span><span class="params">(PropertyValues pvs, Object bean, String beanName)</span> &#123;</span><br><span class="line">    <span class="comment">// 1.首先获取需要进行依赖注入的元信息</span></span><br><span class="line">    <span class="type">InjectionMetadata</span> <span class="variable">metadata</span> <span class="operator">=</span> <span class="built_in">this</span>.findAutowiringMetadata(beanName, bean.getClass(), pvs);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 2.执行依赖注入</span></span><br><span class="line">        metadata.inject(bean, beanName, pvs);</span><br><span class="line">        <span class="keyword">return</span> pvs;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (BeanCreationException var6) &#123;</span><br><span class="line">        <span class="keyword">throw</span> var6;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable var7) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BeanCreationException</span>(beanName, <span class="string">&quot;Injection of autowired dependencies failed&quot;</span>, var7);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们可以使用反射手动调用<code>findAutowiringMetadata()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DigInAutowired</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultListableBeanFactory</span>();</span><br><span class="line">        <span class="comment">// 创建过程,依赖注入,初始化</span></span><br><span class="line">        beanFactory.registerSingleton(<span class="string">&quot;bean2&quot;</span>, <span class="keyword">new</span> <span class="title class_">Bean2</span>()); </span><br><span class="line">        beanFactory.registerSingleton(<span class="string">&quot;bean3&quot;</span>, <span class="keyword">new</span> <span class="title class_">Bean3</span>());</span><br><span class="line">        beanFactory.setAutowireCandidateResolver(<span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>()); <span class="comment">// @Value解析</span></span><br><span class="line">        beanFactory.addEmbeddedValueResolver(<span class="keyword">new</span> <span class="title class_">StandardEnvironment</span>()::resolvePlaceholders); <span class="comment">// $&#123;&#125; 的解析器</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata</span></span><br><span class="line">        <span class="type">AutowiredAnnotationBeanPostProcessor</span> <span class="variable">processor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AutowiredAnnotationBeanPostProcessor</span>();</span><br><span class="line">        processor.setBeanFactory(beanFactory);</span><br><span class="line">        </span><br><span class="line">          <span class="type">Bean1</span> <span class="variable">bean1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line"><span class="comment">//        System.out.println(bean1);</span></span><br><span class="line"><span class="comment">//        processor.postProcessProperties(null, bean1, &quot;bean1&quot;); // 执行依赖注入 @Autowired @Value</span></span><br><span class="line"><span class="comment">//        System.out.println(bean1);</span></span><br><span class="line"></span><br><span class="line">        <span class="type">Method</span> <span class="variable">findAutowiringMetadata</span> <span class="operator">=</span> AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod(<span class="string">&quot;findAutowiringMetadata&quot;</span>, String.class, Class.class, PropertyValues.class);</span><br><span class="line">        findAutowiringMetadata.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">InjectionMetadata</span> <span class="variable">metadata</span> <span class="operator">=</span> (InjectionMetadata) findAutowiringMetadata.invoke(processor, <span class="string">&quot;bean1&quot;</span>, Bean1.class, <span class="literal">null</span>);<span class="comment">// 获取 Bean1 上加了 @Value @Autowired 的成员变量，方法参数信息</span></span><br><span class="line">        System.out.println(metadata);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值</span></span><br><span class="line">        metadata.inject(bean1, <span class="string">&quot;bean1&quot;</span>, <span class="literal">null</span>);</span><br><span class="line">        System.out.println(bean1);</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.beans.factory.annotation.InjectionMetadata@7f0eb4b4</span><br><span class="line">[DEBUG] <span class="number">18</span>:<span class="number">20</span>:<span class="number">14.969</span> [main] com.itheima.a04.Bean1               - <span class="meta">@Value</span> 生效: C:\Path\jdk-<span class="number">14.0</span><span class="number">.1</span> </span><br><span class="line">[DEBUG] <span class="number">18</span>:<span class="number">20</span>:<span class="number">14.976</span> [main] com.itheima.a04.Bean1               - <span class="meta">@Autowired</span> 生效: com.itheima.a04.Bean2@1165b38 </span><br><span class="line">Bean1&#123;bean2=com.itheima.a04.Bean2@1165b38, bean3=com.itheima.a04.Bean3@4c12331b, home=<span class="string">&#x27;C:\Path\jdk-14.0.1&#x27;</span>&#125;</span><br></pre></td></tr></table></figure>

<p>我们发现同样成功进行了依赖注入。</p>
<h3 id="inject"><a href="#inject" class="headerlink" title="inject()"></a>inject()</h3><p><code>inject()</code>方法主要用来执行依赖注入，一般有三种注入方式：</p>
<ul>
<li>根据字段注入</li>
<li>根据set方法注入</li>
<li>根据值注入</li>
</ul>
<p>准备代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DigInAutowired</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">DefaultListableBeanFactory</span> <span class="variable">beanFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultListableBeanFactory</span>();</span><br><span class="line">        beanFactory.registerSingleton(<span class="string">&quot;bean2&quot;</span>, <span class="keyword">new</span> <span class="title class_">Bean2</span>()); <span class="comment">// 创建过程,依赖注入,初始化</span></span><br><span class="line">        beanFactory.registerSingleton(<span class="string">&quot;bean3&quot;</span>, <span class="keyword">new</span> <span class="title class_">Bean3</span>());</span><br><span class="line">        beanFactory.setAutowireCandidateResolver(<span class="keyword">new</span> <span class="title class_">ContextAnnotationAutowireCandidateResolver</span>()); <span class="comment">// @Value</span></span><br><span class="line">        beanFactory.addEmbeddedValueResolver(<span class="keyword">new</span> <span class="title class_">StandardEnvironment</span>()::resolvePlaceholders); <span class="comment">// $&#123;&#125; 的解析器</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata</span></span><br><span class="line">        <span class="type">AutowiredAnnotationBeanPostProcessor</span> <span class="variable">processor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AutowiredAnnotationBeanPostProcessor</span>();</span><br><span class="line">        processor.setBeanFactory(beanFactory);</span><br><span class="line"></span><br><span class="line">        <span class="type">Bean1</span> <span class="variable">bean1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line"><span class="comment">//        System.out.println(bean1);</span></span><br><span class="line"><span class="comment">//        processor.postProcessProperties(null, bean1, &quot;bean1&quot;); // 执行依赖注入 @Autowired @Value</span></span><br><span class="line"><span class="comment">//        System.out.println(bean1);</span></span><br><span class="line"></span><br><span class="line">        <span class="type">Method</span> <span class="variable">findAutowiringMetadata</span> <span class="operator">=</span> AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod(<span class="string">&quot;findAutowiringMetadata&quot;</span>, String.class, Class.class, PropertyValues.class);</span><br><span class="line">        findAutowiringMetadata.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">InjectionMetadata</span> <span class="variable">metadata</span> <span class="operator">=</span> (InjectionMetadata) findAutowiringMetadata.invoke(processor, <span class="string">&quot;bean1&quot;</span>, Bean1.class, <span class="literal">null</span>);<span class="comment">// 获取 Bean1 上加了 @Value @Autowired 的成员变量，方法参数信息</span></span><br><span class="line">        System.out.println(metadata);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值</span></span><br><span class="line">        <span class="comment">//metadata.inject(bean1, &quot;bean1&quot;, null);</span></span><br><span class="line">        <span class="comment">//System.out.println(bean1);</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 3. 如何按类型查找值</span></span><br><span class="line">        <span class="comment">// 根据字段注入</span></span><br><span class="line">        <span class="type">Field</span> <span class="variable">bean3</span> <span class="operator">=</span> Bean1.class.getDeclaredField(<span class="string">&quot;bean3&quot;</span>);</span><br><span class="line">        <span class="type">DependencyDescriptor</span> <span class="variable">dd1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(bean3, <span class="literal">false</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> beanFactory.doResolveDependency(dd1, <span class="literal">null</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        System.out.println(o);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 根据set方法注入</span></span><br><span class="line">        <span class="type">Method</span> <span class="variable">setBean2</span> <span class="operator">=</span> Bean1.class.getDeclaredMethod(<span class="string">&quot;setBean2&quot;</span>, Bean2.class);</span><br><span class="line">        <span class="type">DependencyDescriptor</span> <span class="variable">dd2</span> <span class="operator">=</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(<span class="keyword">new</span> <span class="title class_">MethodParameter</span>(setBean2, <span class="number">0</span>), <span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> beanFactory.doResolveDependency(dd2, <span class="literal">null</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        System.out.println(o1);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 根据值注入</span></span><br><span class="line">        <span class="type">Method</span> <span class="variable">setHome</span> <span class="operator">=</span> Bean1.class.getDeclaredMethod(<span class="string">&quot;setHome&quot;</span>, String.class);</span><br><span class="line">        <span class="type">DependencyDescriptor</span> <span class="variable">dd3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DependencyDescriptor</span>(<span class="keyword">new</span> <span class="title class_">MethodParameter</span>(setHome, <span class="number">0</span>), <span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">o2</span> <span class="operator">=</span> beanFactory.doResolveDependency(dd3, <span class="literal">null</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        System.out.println(o2);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.beans.factory.annotation.InjectionMetadata@7f0eb4b4</span><br><span class="line">com.itheima.a04.Bean3@7b2bbc3</span><br><span class="line">com.itheima.a04.Bean2@1aafa419</span><br><span class="line">C:\Path\jdk-14.0.1</span><br></pre></td></tr></table></figure>

<h1 id="BeanFactory后处理器"><a href="#BeanFactory后处理器" class="headerlink" title="BeanFactory后处理器"></a>BeanFactory后处理器</h1><h2 id="常用后处理器"><a href="#常用后处理器" class="headerlink" title="常用后处理器"></a>常用后处理器</h2><p>在<code>com.itheima.a05.component</code>包下创建类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean2.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean2</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;我被 Spring 管理啦&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean3</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean3.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean3</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;我被 Spring 管理啦&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean4</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean4.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean4</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;我被 Spring 管理啦&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在<code>com.itheima.a05</code>包下创建类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Bean1</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;我被 Spring 管理啦&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.itheima.a05.component&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Config</span> &#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> Bean1 <span class="title function_">bean1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> SqlSessionFactoryBean <span class="title function_">sqlSessionFactoryBean</span><span class="params">(DataSource dataSource)</span> &#123;</span><br><span class="line">        <span class="type">SqlSessionFactoryBean</span> <span class="variable">sqlSessionFactoryBean</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SqlSessionFactoryBean</span>();</span><br><span class="line">        sqlSessionFactoryBean.setDataSource(dataSource);</span><br><span class="line">        <span class="keyword">return</span> sqlSessionFactoryBean;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean(initMethod = &quot;init&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> DruidDataSource <span class="title function_">dataSource</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">DruidDataSource</span> <span class="variable">dataSource</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DruidDataSource</span>();</span><br><span class="line">        dataSource.setUrl(<span class="string">&quot;jdbc:mysql://localhost:3306/test&quot;</span>);</span><br><span class="line">        dataSource.setUsername(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        dataSource.setPassword(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> dataSource;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在<code>com.itheima.a05</code>包下创建启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A05</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(A05.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// ⬇️GenericApplicationContext 是一个【干净】的容器</span></span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        context.registerBean(<span class="string">&quot;config&quot;</span>, Config.class);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// ⬇️初始化容器</span></span><br><span class="line">        context.refresh();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (String name : context.getBeanDefinitionNames()) &#123;</span><br><span class="line">            System.out.println(name);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// ⬇️销毁容器</span></span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">config</span><br></pre></td></tr></table></figure>

<p>发现只有我们手动注册的<code>Config</code>类在<code>spring</code>容器中，<code>Config</code>类上的注解<code>@ComponentScan(&quot;com.itheima.a05.component&quot;)</code>并没有生效。</p>
<ol>
<li>ConfigurationClassPostProcesso</li>
</ol>
<p><code>ConfigurationClassPostProcessor</code> <code>BeanFactory</code>后处理器的作用是解析<code>@ComponentScan</code>、<code>@Bean</code>、<code>@Import</code>、<code>@ImportResource</code>等注解。</p>
<p>我们在代码中加入<code>ConfigurationClassPostProcessor</code>后处理器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// @ComponentScan @Bean @Import @ImportResource</span></span><br><span class="line">context.registerBean(ConfigurationClassPostProcessor.class); </span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 18:49:37.889 [main] com.itheima.a05.component.Bean2     - 我被 Spring 管理啦 </span><br><span class="line">[DEBUG] 18:49:37.896 [main] com.itheima.a05.component.Bean3     - 我被 Spring 管理啦 </span><br><span class="line">[DEBUG] 18:49:37.910 [main] com.itheima.a05.Bean1               - 我被 Spring 管理啦 </span><br><span class="line">config</span><br><span class="line">org.springframework.context.annotation.ConfigurationClassPostProcessor</span><br><span class="line">bean2</span><br><span class="line">bean3</span><br><span class="line">bean1</span><br></pre></td></tr></table></figure>

<p>我们发现<code>@ComponentScan</code>注解已经生效。</p>
<ol start="2">
<li>MapperScannerConfigurer</li>
</ol>
<p><code>MapperScannerConfigurer</code> <code>BeanFactory</code>后处理器的作用是扫描<code>Mybatis</code>的<code>Mapper</code>接口。</p>
<p>我们在<code>com.itheima.a05.mapper</code>包下创建代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Mapper1</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Mapper2</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在启动类中添加代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(MapperScannerConfigurer.class, bd -&gt; &#123; <span class="comment">// @MapperScanner</span></span><br><span class="line">    bd.getPropertyValues().add(<span class="string">&quot;basePackage&quot;</span>, <span class="string">&quot;com.itheima.a05.mapper&quot;</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>启动<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">//...</span><br><span class="line">mapper1</span><br><span class="line">mapper2</span><br><span class="line">//...</span><br></pre></td></tr></table></figure>

<p>我们发现<code>mapper</code>已被加入到<code>spring</code>中的容器中。</p>
<h2 id="模拟注解实现"><a href="#模拟注解实现" class="headerlink" title="模拟注解实现"></a>模拟注解实现</h2><h3 id="ComponentScan"><a href="#ComponentScan" class="headerlink" title="@ComponentScan"></a>@ComponentScan</h3><p>实现<code>BeanDefinitionRegistryPostProcessor</code>接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ComponentScanPostProcessor</span> <span class="keyword">implements</span> <span class="title class_">BeanDefinitionRegistryPostProcessor</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span> <span class="comment">// context.refresh</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeanFactory</span><span class="params">(ConfigurableListableBeanFactory configurableListableBeanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeanDefinitionRegistry</span><span class="params">(BeanDefinitionRegistry beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">ComponentScan</span> <span class="variable">componentScan</span> <span class="operator">=</span> AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);</span><br><span class="line">            <span class="keyword">if</span> (componentScan != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">for</span> (String p : componentScan.basePackages()) &#123;</span><br><span class="line">                    System.out.println(p);</span><br><span class="line">                    <span class="comment">// com.itheima.a05.component -&gt; classpath*:com/itheima/a05/component/**/*.class</span></span><br><span class="line">                    <span class="type">String</span> <span class="variable">path</span> <span class="operator">=</span> <span class="string">&quot;classpath*:&quot;</span> + p.replace(<span class="string">&quot;.&quot;</span>, <span class="string">&quot;/&quot;</span>) + <span class="string">&quot;/**/*.class&quot;</span>;</span><br><span class="line">                    System.out.println(path);</span><br><span class="line">                    <span class="type">CachingMetadataReaderFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CachingMetadataReaderFactory</span>();</span><br><span class="line">                    Resource[] resources = <span class="keyword">new</span> <span class="title class_">PathMatchingResourcePatternResolver</span>().getResources(path);</span><br><span class="line">                    <span class="type">AnnotationBeanNameGenerator</span> <span class="variable">generator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationBeanNameGenerator</span>();</span><br><span class="line">                    <span class="keyword">for</span> (Resource resource : resources) &#123;</span><br><span class="line">                        <span class="comment">// System.out.println(resource);</span></span><br><span class="line">                        <span class="type">MetadataReader</span> <span class="variable">reader</span> <span class="operator">=</span> factory.getMetadataReader(resource);</span><br><span class="line">                        <span class="comment">// System.out.println(&quot;类名:&quot; + reader.getClassMetadata().getClassName());</span></span><br><span class="line">                        <span class="type">AnnotationMetadata</span> <span class="variable">annotationMetadata</span> <span class="operator">=</span> reader.getAnnotationMetadata();</span><br><span class="line">                        <span class="comment">// System.out.println(&quot;是否加了 @Component:&quot; + annotationMetadata.hasAnnotation(Component.class.getName()));</span></span><br><span class="line">                        <span class="comment">// System.out.println(&quot;是否加了 @Component 派生:&quot; + annotationMetadata.hasMetaAnnotation(Component.class.getName()));</span></span><br><span class="line">                        <span class="keyword">if</span> (annotationMetadata.hasAnnotation(Component.class.getName())</span><br><span class="line">                            || annotationMetadata.hasMetaAnnotation(Component.class.getName())) &#123;</span><br><span class="line">                            <span class="type">AbstractBeanDefinition</span> <span class="variable">bd</span> <span class="operator">=</span> BeanDefinitionBuilder</span><br><span class="line">                                    .genericBeanDefinition(reader.getClassMetadata().getClassName())</span><br><span class="line">                                    .getBeanDefinition();</span><br><span class="line">                            <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> generator.generateBeanName(bd, beanFactory);</span><br><span class="line">                            beanFactory.registerBeanDefinition(name, bd);</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>主要步骤：</p>
<ol>
<li>获取<code>@ComponentScan</code>注解</li>
<li>获取<code>@ComponentScan</code>注解上的值<code>basePackages</code></li>
<li>转换扫描包为真实路径</li>
<li>解析路径获取<code>resource</code></li>
<li>根据<code>resource</code>获取元信息</li>
<li>判断是否直接或间接拥有<code>@Component</code>注解</li>
<li>注册<code>BeanDefinition</code></li>
</ol>
<p>在<code>main()</code>方法中注册自己编写的<code>ComponentScanPostProcessor</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(ComponentScanPostProcessor.class); <span class="comment">// 解析 @ComponentScan</span></span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台，发现能够解析被<code>@Component</code>注解修饰的类：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">//...</span><br><span class="line">bean2</span><br><span class="line">bean3</span><br></pre></td></tr></table></figure>

<h3 id="Bean"><a href="#Bean" class="headerlink" title="@Bean"></a>@Bean</h3><p>实现<code>BeanDefinitionRegistryPostProcessor</code>接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AtBeanPostProcessor</span> <span class="keyword">implements</span> <span class="title class_">BeanDefinitionRegistryPostProcessor</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeanFactory</span><span class="params">(ConfigurableListableBeanFactory configurableListableBeanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeanDefinitionRegistry</span><span class="params">(BeanDefinitionRegistry beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">CachingMetadataReaderFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CachingMetadataReaderFactory</span>();</span><br><span class="line">            <span class="comment">// 读取元信息</span></span><br><span class="line">            <span class="type">MetadataReader</span> <span class="variable">reader</span> <span class="operator">=</span> factory.getMetadataReader(<span class="keyword">new</span> <span class="title class_">ClassPathResource</span>(<span class="string">&quot;com/itheima/a05/Config.class&quot;</span>));</span><br><span class="line">            <span class="comment">// 获取被@Bean注解标注的方法信息</span></span><br><span class="line">            Set&lt;MethodMetadata&gt; methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());</span><br><span class="line">            <span class="keyword">for</span> (MethodMetadata method : methods) &#123;</span><br><span class="line">                System.out.println(method);</span><br><span class="line">                <span class="comment">// 获取初始化方法名称</span></span><br><span class="line">                <span class="type">String</span> <span class="variable">initMethod</span> <span class="operator">=</span> method.getAnnotationAttributes(Bean.class.getName()).get(<span class="string">&quot;initMethod&quot;</span>).toString();</span><br><span class="line">                <span class="comment">// 创建BeanDefinitionBuilder</span></span><br><span class="line">                <span class="type">BeanDefinitionBuilder</span> <span class="variable">builder</span> <span class="operator">=</span> BeanDefinitionBuilder.genericBeanDefinition();</span><br><span class="line">                <span class="comment">// 设置factoryBean</span></span><br><span class="line">                builder.setFactoryMethodOnBean(method.getMethodName(), <span class="string">&quot;config&quot;</span>);</span><br><span class="line">                <span class="comment">// 设置自动装配模式</span></span><br><span class="line">                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);</span><br><span class="line">                <span class="keyword">if</span> (initMethod.length() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="comment">// 对初始化方法进行解析</span></span><br><span class="line">                    builder.setInitMethodName(initMethod);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="type">AbstractBeanDefinition</span> <span class="variable">bd</span> <span class="operator">=</span> builder.getBeanDefinition();</span><br><span class="line">                <span class="comment">// 注册Bean</span></span><br><span class="line">                beanFactory.registerBeanDefinition(method.getMethodName(), bd);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>主要步骤：</p>
<ol>
<li>根据类获取元信息</li>
<li>获取被<code>@Bean</code>注解标注的方法信息</li>
<li>创建<code>BeanDefinitionBuilder</code></li>
<li>设置自动装配模式，用于依赖注入</li>
<li>注册<code>Bean</code></li>
</ol>
<blockquote>
<p>还可以根据需要设置初始化方法</p>
</blockquote>
<p>在<code>main()</code>方法中注册自己编写的<code>AtBeanPostProcessor</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(AtBeanPostProcessor.class); <span class="comment">// 解析 @Bean</span></span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台，发现Config类中被<code>@Bean</code>注解修饰的方法已经生效：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">//...</span><br><span class="line">bean1</span><br><span class="line">sqlSessionFactoryBean</span><br><span class="line">dataSource</span><br><span class="line">//...</span><br></pre></td></tr></table></figure>

<h3 id="Mapper"><a href="#Mapper" class="headerlink" title="@Mapper"></a>@Mapper</h3><p>在<code>Config</code>类中添加<code>Bean</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> MapperFactoryBean&lt;Mapper1&gt; <span class="title function_">mapper1</span><span class="params">(SqlSessionFactory sqlSessionFactory)</span> &#123;</span><br><span class="line">    MapperFactoryBean&lt;Mapper1&gt; factory = <span class="keyword">new</span> <span class="title class_">MapperFactoryBean</span>&lt;&gt;(Mapper1.class);</span><br><span class="line">    factory.setSqlSessionFactory(sqlSessionFactory);</span><br><span class="line">    <span class="keyword">return</span> factory;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> MapperFactoryBean&lt;Mapper2&gt; <span class="title function_">mapper2</span><span class="params">(SqlSessionFactory sqlSessionFactory)</span> &#123;</span><br><span class="line">    MapperFactoryBean&lt;Mapper2&gt; factory = <span class="keyword">new</span> <span class="title class_">MapperFactoryBean</span>&lt;&gt;(Mapper2.class);</span><br><span class="line">    factory.setSqlSessionFactory(sqlSessionFactory);</span><br><span class="line">    <span class="keyword">return</span> factory;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实现<code>BeanDefinitionRegistryPostProcessor</code>接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MapperPostProcessor</span> <span class="keyword">implements</span> <span class="title class_">BeanDefinitionRegistryPostProcessor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeanDefinitionRegistry</span><span class="params">(BeanDefinitionRegistry beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 创建resource解析器</span></span><br><span class="line">            <span class="type">PathMatchingResourcePatternResolver</span> <span class="variable">resolver</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PathMatchingResourcePatternResolver</span>();</span><br><span class="line">            <span class="comment">// 获取resource</span></span><br><span class="line">            Resource[] resources = resolver.getResources(<span class="string">&quot;classpath:com/itheima/a05/mapper/**/*.class&quot;</span>);</span><br><span class="line">            <span class="type">AnnotationBeanNameGenerator</span> <span class="variable">generator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationBeanNameGenerator</span>();</span><br><span class="line">            <span class="type">CachingMetadataReaderFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CachingMetadataReaderFactory</span>();</span><br><span class="line">            <span class="keyword">for</span> (Resource resource : resources) &#123;</span><br><span class="line">                <span class="type">MetadataReader</span> <span class="variable">reader</span> <span class="operator">=</span> factory.getMetadataReader(resource);</span><br><span class="line">                <span class="comment">// 获取类元信息</span></span><br><span class="line">                <span class="type">ClassMetadata</span> <span class="variable">classMetadata</span> <span class="operator">=</span> reader.getClassMetadata();</span><br><span class="line">                <span class="keyword">if</span> (classMetadata.isInterface()) &#123;</span><br><span class="line">                    <span class="comment">// 获取BeanDefinition</span></span><br><span class="line">                    <span class="type">AbstractBeanDefinition</span> <span class="variable">bd</span> <span class="operator">=</span> BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)</span><br><span class="line">                            <span class="comment">// 根据名称调用MapperFactoryBean构造方法</span></span><br><span class="line">                            .addConstructorArgValue(classMetadata.getClassName())</span><br><span class="line">                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)</span><br><span class="line">                            .getBeanDefinition();</span><br><span class="line">                    <span class="comment">// 获取接口名作为Bean的名称</span></span><br><span class="line">                    <span class="type">AbstractBeanDefinition</span> <span class="variable">bd2</span> <span class="operator">=</span> BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();</span><br><span class="line">                    <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> generator.generateBeanName(bd2, beanFactory);</span><br><span class="line">                    <span class="comment">// 注册Bean</span></span><br><span class="line">                    beanFactory.registerBeanDefinition(name, bd);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">postProcessBeanFactory</span><span class="params">(ConfigurableListableBeanFactory beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>主要步骤：</p>
<ol>
<li>创建<code>resource</code>解析器</li>
<li>获取<code>resource</code></li>
<li>获取类元信息</li>
<li>获取<code>BeanDefinition</code></li>
<li>获取接口名作为<code>Bean</code>的名称</li>
<li>注册<code>Bean</code></li>
</ol>
<p>在<code>main()</code>方法中注册自己编写的<code>MapperPostProcessor</code>类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(MapperPostProcessor.class); <span class="comment">// 解析 Mapper 接口</span></span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台，发现<code>com/itheima/a05/mapper</code>包中被<code>@MapperScan</code>注解修饰的方法已经生效：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">//...</span><br><span class="line">mapper1</span><br><span class="line">mapper2</span><br><span class="line">//...</span><br></pre></td></tr></table></figure>

<h1 id="Aware接口"><a href="#Aware接口" class="headerlink" title="Aware接口"></a>Aware接口</h1><h2 id="Aware与InitializingBean接口"><a href="#Aware与InitializingBean接口" class="headerlink" title="Aware与InitializingBean接口"></a>Aware与InitializingBean接口</h2><p><code>Aware</code>接口用于注入一些与容器相关信息, 例如</p>
<ol>
<li><code>BeanNameAware</code>注入<code>bean</code>的名字</li>
<li><code>BeanFactoryAware</code>注入<code>BeanFactory </code>容器</li>
<li><code>ApplicationContextAware</code>注入<code>ApplicationContext </code>容器</li>
<li><code>EmbeddedValueResolverAware</code>解析表达式，例如：${}</li>
</ol>
<p><code>InitializingBean</code>接口提供内置的初始化手段。</p>
<p>创建类<code>MyBean</code>并实现<code>BeanNameAware</code>、<code>ApplicationContextAware</code>、<code>InitializingBean</code>接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyBean</span> <span class="keyword">implements</span> <span class="title class_">BeanNameAware</span>, ApplicationContextAware, InitializingBean &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyBean.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setBeanName</span><span class="params">(String name)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;当前bean &quot;</span> + <span class="built_in">this</span> + <span class="string">&quot; 名字叫:&quot;</span> + name);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setApplicationContext</span><span class="params">(ApplicationContext applicationContext)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;当前bean &quot;</span> + <span class="built_in">this</span> + <span class="string">&quot; 容器是:&quot;</span> + applicationContext);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;当前bean &quot;</span> + <span class="built_in">this</span> + <span class="string">&quot; 初始化&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A06</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(A06.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        context.registerBean(<span class="string">&quot;myBean&quot;</span>, MyBean.class);</span><br><span class="line">        context.refresh(); </span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行<code>main()</code>方法，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:01:21.092 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@20deea7f 名字叫:myBean </span><br><span class="line">[DEBUG] 21:01:21.118 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@20deea7f 容器是:org.springframework.context.support.GenericApplicationContext@32464a14, started on Sun Mar 26 21:01:21 CST 2023 </span><br><span class="line">[DEBUG] 21:01:21.121 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@20deea7f 初始化 </span><br></pre></td></tr></table></figure>

<p>发现我们实现的方法都被调用。</p>
<p><code>Aware</code>接口的功能<code>@Autowired</code>就能实现, 为啥还要用<code>Aware</code>接口呢？</p>
<ol>
<li><code>@Autowired</code>的解析需要用到<code>bean</code>后处理器, 属于扩展功能</li>
<li>而<code>Aware</code>接口属于内置功能, 不加任何扩展, <code>Spring</code>就能识别</li>
</ol>
<blockquote>
<p>某些情况下, 扩展功能会失效, 而内置功能不会失效</p>
</blockquote>
<p>这里做一个测试，在<code>MyBean</code>类中添加如下方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">aaa</span><span class="params">(ApplicationContext applicationContext)</span> &#123;</span><br><span class="line">    log.debug(<span class="string">&quot;当前bean &quot;</span> + <span class="built_in">this</span> + <span class="string">&quot; 使用@Autowired 容器是:&quot;</span> + applicationContext);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@PostConstruct</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">    log.debug(<span class="string">&quot;当前bean &quot;</span> + <span class="built_in">this</span> + <span class="string">&quot; 使用@PostConstruct 初始化&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们必须在启动类中添加相应的Bean后处理器，<code>@Autowired</code>、<code>@PostConstruct</code>注解才能生效：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">context.registerBean(AutowiredAnnotationBeanPostProcessor.class);</span><br><span class="line">context.registerBean(CommonAnnotationBeanPostProcessor.class);</span><br></pre></td></tr></table></figure>

<p>查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:07:23.998 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@d21a74c 使用@Autowired 容器是:org.springframework.context.support.GenericApplicationContext@32464a14, started on Sun Mar 26 21:07:23 CST 2023 </span><br><span class="line">[DEBUG] 21:07:24.004 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@d21a74c 名字叫:myBean </span><br><span class="line">[DEBUG] 21:07:24.004 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@d21a74c 容器是:org.springframework.context.support.GenericApplicationContext@32464a14, started on Sun Mar 26 21:07:23 CST 2023 </span><br><span class="line">[DEBUG] 21:07:24.007 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@d21a74c 使用@PostConstruct 初始化 </span><br><span class="line">[DEBUG] 21:07:24.008 [main] com.itheima.a06.MyBean              - 当前bean com.itheima.a06.MyBean@d21a74c 初始化 </span><br></pre></td></tr></table></figure>

<h2 id="注解失效分析"><a href="#注解失效分析" class="headerlink" title="注解失效分析"></a>注解失效分析</h2><p>准备<code>MyConfig1</code>类，注意其中添加了一个<code>beanFactory</code>后处理器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfig1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyConfig1.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setApplicationContext</span><span class="params">(ApplicationContext applicationContext)</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;注入 ApplicationContext&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;初始化&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span> <span class="comment">//  beanFactory 后处理器</span></span><br><span class="line">    <span class="keyword">public</span> BeanFactoryPostProcessor <span class="title function_">processor1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> beanFactory -&gt; &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;执行 processor1&quot;</span>);</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A06</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(A06.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">GenericApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GenericApplicationContext</span>();</span><br><span class="line">        </span><br><span class="line">        context.registerBean(<span class="string">&quot;myConfig1&quot;</span>, MyConfig1.class);</span><br><span class="line">        </span><br><span class="line">        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);</span><br><span class="line">        context.registerBean(CommonAnnotationBeanPostProcessor.class);</span><br><span class="line">        context.registerBean(ConfigurationClassPostProcessor.class);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        context.refresh(); </span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:20:02.446 [main] com.itheima.a06.MyConfig1           - 执行 processor1 </span><br></pre></td></tr></table></figure>

<p>发现<code>@Autowired</code>、<code>@PostConstruct</code>注解失效。</p>
<p><code>context.refresh()</code>的执行顺序：</p>
<ol>
<li><code>BeanFactory</code>后处理器</li>
<li>添加<code>bean</code>后处理器</li>
<li>初始化单例</li>
</ol>
<p><code>Java</code>配置类不包含<code>BeanFactoryPostProcessor</code>的情况：</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/10.png" alt="img"></p>
<p><code>Java</code>配置类包含<code>BeanFactoryPostProcessor</code>的情况，因此要创建其中的<code>BeanFactoryPostProcessor</code>必须提前创建<code>Java</code>配置类，而此时的<code>BeanPostProcessor</code>还未准备好，导致<code>@Autowired</code>等注解失效</p>
<p><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/11.png" alt="img"></p>
<p>使用内置的<code>InitializingBean</code>接口和<code>ApplicationContextAware</code>则不会失效：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyConfig2</span> <span class="keyword">implements</span> <span class="title class_">InitializingBean</span>, ApplicationContextAware &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(MyConfig2.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;初始化&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setApplicationContext</span><span class="params">(ApplicationContext applicationContext)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;注入 ApplicationContext&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span> <span class="comment">//  beanFactory 后处理器</span></span><br><span class="line">    <span class="keyword">public</span> BeanFactoryPostProcessor <span class="title function_">processor2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> beanFactory -&gt; &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;执行 processor2&quot;</span>);</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，控制台输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:27:31.312 [main] com.itheima.a06.MyConfig2           - 注入 ApplicationContext </span><br><span class="line">[DEBUG] 21:27:31.318 [main] com.itheima.a06.MyConfig2           - 初始化 </span><br><span class="line">[INFO ] 21:27:31.321 [main] o.s.c.a.ConfigurationClassEnhancer  - @Bean method MyConfig2.processor2 is non-static and returns an object assignable to Spring&#x27;s BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method&#x27;s declaring @Configuration class. Add the &#x27;static&#x27; modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details. </span><br><span class="line">[DEBUG] 21:27:31.333 [main] com.itheima.a06.MyConfig2           - 执行 processor2 </span><br></pre></td></tr></table></figure>

<h1 id="初始化与销毁"><a href="#初始化与销毁" class="headerlink" title="初始化与销毁"></a>初始化与销毁</h1><h2 id="初始化方法"><a href="#初始化方法" class="headerlink" title="初始化方法"></a>初始化方法</h2><p>创建<code>Bean1</code>类，分别使用了三种初始化方法：</p>
<ol>
<li>使用<code>@PostConstruct</code>注解初始化</li>
<li>实现接口<code>InitializingBean</code>的<code>afterPropertiesSet()</code>方法</li>
<li>使用<code>@Bean(initMethod = &quot;init3&quot;)</code>注解的<code>initMethod</code>属性</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean1</span> <span class="keyword">implements</span> <span class="title class_">InitializingBean</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean1.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init1</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;初始化1&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;初始化2&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init3</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;初始化3&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>创建启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A07_1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> SpringApplication.run(A07_1.class, args);</span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean(initMethod = &quot;init3&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Bean1 <span class="title function_">bean1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean1</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:34:09.944 [main] com.itheima.a07.Bean1               - 初始化1 </span><br><span class="line">[DEBUG] 21:34:09.944 [main] com.itheima.a07.Bean1               - 初始化2 </span><br><span class="line">[DEBUG] 21:34:09.944 [main] com.itheima.a07.Bean1               - 初始化3 </span><br></pre></td></tr></table></figure>

<p>初始化方法顺序：</p>
<ol>
<li><code>@PostConstruct</code>注解初始化</li>
<li>接口<code>InitializingBean</code>的<code>afterPropertiesSet()</code>方法初始化</li>
<li><code>@Bean(initMethod = &quot;init3&quot;)</code>注解的<code>initMethod</code>属性初始化</li>
</ol>
<h2 id="销毁方法"><a href="#销毁方法" class="headerlink" title="销毁方法"></a>销毁方法</h2><p>创建<code>Bean2</code>类，分别使用了三种销毁方法：</p>
<ol>
<li>使用<code>@PreDestroy</code>注解销毁</li>
<li>实现接口<code>DisposableBean</code>的<code>destroy()</code>方法销毁</li>
<li>使用<code>@Bean(destroyMethod </code><strong><code>= &quot;</code></strong><code>destroy3</code><strong><code>&quot;</code></strong><code>)</code>注解的<code>destroyMethod</code>属性销毁</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bean2</span> <span class="keyword">implements</span> <span class="title class_">DisposableBean</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(Bean2.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy1</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;销毁1&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;销毁2&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy3</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;销毁3&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A07_1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">ConfigurableApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span> SpringApplication.run(A07_1.class, args);</span><br><span class="line">        context.close();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean(destroyMethod = &quot;destroy3&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> Bean2 <span class="title function_">bean2</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Bean2</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 21:34:10.565 [main] com.itheima.a07.Bean2               - 销毁1 </span><br><span class="line">[DEBUG] 21:34:10.566 [main] com.itheima.a07.Bean2               - 销毁2 </span><br><span class="line">[DEBUG] 21:34:10.566 [main] com.itheima.a07.Bean2               - 销毁3 </span><br></pre></td></tr></table></figure>

<p>销毁方法执行顺序：</p>
<ol>
<li><code>@PreDestroy</code>注解销毁</li>
<li>接口<code>DisposableBean</code>的<code>destroy()</code>方法销毁</li>
<li><code>@Bean(destroyMethod </code><strong><code>= &quot;</code></strong><code>destroy3</code><strong><code>&quot;</code></strong><code>)</code>注解的<code>destroyMethod</code>属性销毁</li>
</ol>
<h1 id="Scope"><a href="#Scope" class="headerlink" title="Scope"></a>Scope</h1><h2 id="Scope的类型与销毁"><a href="#Scope的类型与销毁" class="headerlink" title="Scope的类型与销毁"></a>Scope的类型与销毁</h2><p>scope的类型有以下五种：</p>
<ul>
<li><code>singleton</code>：这是<code>Spring</code>默认的<code>scope</code>，表示<code>Spring</code>容器只创建唯一个<code>bean</code>的实例，所有该对象的引用都共享这个实例，并且<code>Spring</code>在创建第一次后，会在<code>Spring</code>的<code>IoC</code>容器中缓存起来，之后不再创建。这就是设计模式中的单例模式的形式。并且对该<code>bean</code>的所有后续请求和引用都将返回该缓存中的对象实例。一般情况下，无状态的<code>bean</code>使用该<code>scope</code>。</li>
<li><code>prototype</code>：代表线程每次调用或请求这个<code>bean</code>都会创建一个新的实例，一般情况下，有状态的<code>bean</code>使用该<code>scope</code>。</li>
<li><code>request</code>：每次<code>http</code>请求将会有各自的<code>bean</code>实例，类似于<code>prototype</code>，也就是说每个<code>request</code>作用域内的请求只创建一个实例。</li>
<li><code>session</code>：在一个<code>http session</code>中，一个bean<code>定义</code>对应一个<code>bean</code>实例，也就是说每个<code>session</code>作用域内的请求只创建一个实例。</li>
<li><code>application</code>：全局<code>web</code>应用级别，也是在<code>web</code>环境中使用的，一个<code>web</code>应用程序对应一个<code>bean</code>实例，通常情况下和<code>singleton</code>效果类似的，不过也有不一样的地方，<code>singleton</code>是每个<code>spring</code>容器中只有一个<code>bean</code>实例，一般我们的程序只有一个<code>spring</code>容器，但是，一个应用程序中可以创建多个<code>spring</code>容器，不同的容器中可以存在同名的<code>bean</code>，但是<code>scope=aplication</code>的时候，不管应用中有多少个<code>spring</code>容器，这个应用中同名的<code>bean</code>只有一个</li>
</ul>
<p>准备三个不同作用域的Bean：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Scope(&quot;application&quot;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BeanForApplication</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(BeanForApplication.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Scope(&quot;request&quot;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BeanForRequest</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(BeanForRequest.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Scope(&quot;session&quot;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BeanForSession</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(BeanForSession.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;destroy&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写<code>Controller</code>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Lazy</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> BeanForRequest beanForRequest;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Lazy</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> BeanForSession beanForSession;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Lazy</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> BeanForApplication beanForApplication;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(value = &quot;/test&quot;, produces = &quot;text/html&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">test</span><span class="params">(HttpServletRequest request, HttpSession session)</span> &#123;</span><br><span class="line">        <span class="type">ServletContext</span> <span class="variable">sc</span> <span class="operator">=</span> request.getServletContext();</span><br><span class="line">        <span class="type">String</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="string">&quot;&lt;ul&gt;&quot;</span> +</span><br><span class="line">                    <span class="string">&quot;&lt;li&gt;&quot;</span> + <span class="string">&quot;request scope:&quot;</span> + beanForRequest + <span class="string">&quot;&lt;/li&gt;&quot;</span> +</span><br><span class="line">                    <span class="string">&quot;&lt;li&gt;&quot;</span> + <span class="string">&quot;session scope:&quot;</span> + beanForSession + <span class="string">&quot;&lt;/li&gt;&quot;</span> +</span><br><span class="line">                    <span class="string">&quot;&lt;li&gt;&quot;</span> + <span class="string">&quot;application scope:&quot;</span> + beanForApplication + <span class="string">&quot;&lt;/li&gt;&quot;</span> +</span><br><span class="line">                    <span class="string">&quot;&lt;/ul&gt;&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> sb;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>编写启动类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">    singleton, prototype, request, session, application</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    jdk &gt;= 9 如果反射调用 jdk 中方法</span></span><br><span class="line"><span class="comment">    jdk &lt;= 8 不会有问题</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    演示 request, session, application 作用域</span></span><br><span class="line"><span class="comment">    打开不同的浏览器, 刷新 http://localhost:8080/test 即可查看效果</span></span><br><span class="line"><span class="comment">    如果 jdk &gt; 8, 运行时请添加 --add-opens java.base/java.lang=ALL-UNNAMED</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A08</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        SpringApplication.run(A08.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，访问<a target="_blank" rel="noopener" href="http://localhost:8080/test%EF%BC%8C%E6%B5%8F%E8%A7%88%E5%99%A8%E5%87%BA%E7%8E%B0%EF%BC%9A">http://localhost:8080/test，浏览器出现：</a></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">request scope:com.itheima.a08.BeanForRequest@14742c57</span><br><span class="line">session scope:com.itheima.a08.BeanForSession@2f6cff45</span><br><span class="line">application scope:com.itheima.a08.BeanForApplication@3b82843b</span><br></pre></td></tr></table></figure>

<p>每当我们刷新一次页面<code>BeanForRequest</code>的地址就会变化，说明<code>request</code>作用范围在一次请求中。当<code>session</code>会话过期，我们刷新页面<code>BeanForSession</code>的地址也会变化，说明<code>session</code>作用范围在一次会话中。当我们停止启动类，<code>BeanForApplication</code>会被销毁，说明<code>application</code>作用范围与容器生命周期一样长。</p>
<h2 id="Scope失效解决方法"><a href="#Scope失效解决方法" class="headerlink" title="Scope失效解决方法"></a>Scope失效解决方法</h2><p><strong>Scope失效情况演示</strong></p>
<p>准备如下类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//E为单例，依赖F1类(为多例)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">E</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> F1 f1;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> F1 <span class="title function_">getF1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> f1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//F1为多例</span></span><br><span class="line"><span class="meta">@Scope(&quot;prototype&quot;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">F1</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//启动类</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;com.itheima.a08.sub&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A08_1</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(A08_1.class);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">AnnotationConfigApplicationContext</span> <span class="variable">context</span> <span class="operator">=</span></span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">AnnotationConfigApplicationContext</span>(A08_1.class);</span><br><span class="line"></span><br><span class="line">        <span class="type">E</span> <span class="variable">e</span> <span class="operator">=</span> context.getBean(E.class);</span><br><span class="line">        log.debug(<span class="string">&quot;&#123;&#125;&quot;</span>, e.getF1());</span><br><span class="line">        log.debug(<span class="string">&quot;&#123;&#125;&quot;</span>, e.getF1());</span><br><span class="line">        log.debug(<span class="string">&quot;&#123;&#125;&quot;</span>, e.getF1());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] <span class="number">23</span>:<span class="number">17</span>:<span class="number">58.864</span> [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@30bce90b </span><br><span class="line">[DEBUG] <span class="number">23</span>:<span class="number">17</span>:<span class="number">58.864</span> [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@30bce90b </span><br><span class="line">[DEBUG] <span class="number">23</span>:<span class="number">17</span>:<span class="number">58.864</span> [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@30bce90b </span><br></pre></td></tr></table></figure>

<p>我们发现E中的F1类地址始终为一个，说明多例失效了。</p>
<h3 id="解决方式一"><a href="#解决方式一" class="headerlink" title="解决方式一"></a>解决方式一</h3><p>添加<code>@Lazy</code>注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">E</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Lazy</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> F1 f1;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> F1 <span class="title function_">getF1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> f1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:21:02.385 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@4196c360 </span><br><span class="line">[DEBUG] 23:21:02.409 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@225129c </span><br><span class="line">[DEBUG] 23:21:02.410 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@573906eb </span><br></pre></td></tr></table></figure>

<p>我们发现E中的F1类地址每次都变化，说明多例生效了。</p>
<p>事实上使用<code>@Lazy</code>注解，<code>spring</code>会为我们创建一个代理类，打印F类实例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">log.debug(<span class="string">&quot;&#123;&#125;&quot;</span>, e.getF1().getClass());</span><br></pre></td></tr></table></figure>

<p>查看输出：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:21:02.378 [main] com.itheima.a08.A08_1               - class com.itheima.a08.sub.F1$$EnhancerBySpringCGLIB$$21b324fd </span><br></pre></td></tr></table></figure>

<p>发现是一个使用了<code>cglib</code>代理的类。</p>
<h3 id="解决方式二"><a href="#解决方式二" class="headerlink" title="解决方式二"></a>解决方式二</h3><p>设置<code>proxyMode=ScopedProxyMode.TARGET_CLASS</code>，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Scope(value = &quot;prototype&quot;, proxyMode = ScopedProxyMode.TARGET_CLASS)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">F1</span> &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:26:28.666 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@7c214cc0 </span><br><span class="line">[DEBUG] 23:26:28.696 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@609db546 </span><br><span class="line">[DEBUG] 23:26:28.696 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@56c4278e </span><br></pre></td></tr></table></figure>

<p><code>spring</code>同样为我们创建了代理类：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:26:28.658 [main] com.itheima.a08.A08_1               - class com.itheima.a08.sub.F1$$EnhancerBySpringCGLIB$$21b324fd </span><br></pre></td></tr></table></figure>

<h3 id="解决方式三"><a href="#解决方式三" class="headerlink" title="解决方式三"></a>解决方式三</h3><p>使用<code>ObjectFactory</code>工厂，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">E</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ObjectFactory&lt;F3&gt; f1;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> F3 <span class="title function_">getF1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> f1.getObject();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:30:58.390 [main] com.itheima.a08.A08_1               - class com.itheima.a08.sub.F1</span><br><span class="line">[DEBUG] 23:30:58.390 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@59cba5a </span><br><span class="line">[DEBUG] 23:30:58.390 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@6f19ac19 </span><br><span class="line">[DEBUG] 23:30:58.390 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@71329995 </span><br></pre></td></tr></table></figure>

<p>我们发现这种方式没有给我们创建代理。</p>
<h3 id="解决方式四"><a href="#解决方式四" class="headerlink" title="解决方式四"></a>解决方式四</h3><p>使用<code>ApplicationContext</code>，例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">E</span> &#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationContext context;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> F4 <span class="title function_">getF1</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> context.getBean(F1.class);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行启动类，查看控制台：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[DEBUG] 23:34:15.926 [main] com.itheima.a08.A08_1               - class com.itheima.a08.sub.F1 </span><br><span class="line">[DEBUG] 23:34:15.926 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@768fc0f2 </span><br><span class="line">[DEBUG] 23:34:15.926 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@5454d35e </span><br><span class="line">[DEBUG] 23:34:15.926 [main] com.itheima.a08.A08_1               - com.itheima.a08.sub.F1@20c0a64d </span><br></pre></td></tr></table></figure>

<p>我们发现这种方式没有给我们创建代理。</p>
<blockquote>
<p>以上解决方式实际上都是延迟了多例对象的创建，使其在运行时创建，而不是在一开始就初始化完成。</p>
</blockquote>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href>狼族少年、血狼</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://geekwolfman.github.io/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC.html">https://geekwolfman.github.io/2023/04/15/Spring高级45讲【第二章】：IOC.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://geekwolfman.github.io" target="_blank">狼族少年、血狼</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/spring/">spring</a></div><div class="post_share"><div class="social-share" data-image="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%8C%E7%AB%A0%E3%80%91%EF%BC%9AIOC/01cover.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP.html" title="Spring高级45讲【第三章】：AOP"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Spring高级45讲【第三章】：AOP</div></div></a></div><div class="next-post pull-right"><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6.html" title="Spring高级45讲【第一章】：导学"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6/01cover.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring高级45讲【第一章】：导学</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER.html" title="Spring高级45讲【第六章】：OTHER"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%85%AD%E7%AB%A0%E3%80%91%EF%BC%9AOTHER/00cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第六章】：OTHER</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT.html" title="Spring高级45讲【第五章】：BOOT"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%BA%94%E7%AB%A0%E3%80%91%EF%BC%9ABOOT/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第五章】：BOOT</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB.html" title="Spring高级45讲【第四章】：WEB"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E5%9B%9B%E7%AB%A0%E3%80%91%EF%BC%9AWEB/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第四章】：WEB</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP.html" title="Spring高级45讲【第三章】：AOP"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%89%E7%AB%A0%E3%80%91%EF%BC%9AAOP/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第三章】：AOP</div></div></a></div><div><a href="/2023/04/15/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6.html" title="Spring高级45讲【第一章】：导学"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/Spring%E9%AB%98%E7%BA%A745%E8%AE%B2%E3%80%90%E7%AC%AC%E4%B8%80%E7%AB%A0%E3%80%91%EF%BC%9A%E5%AF%BC%E5%AD%A6/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-15</div><div class="title">Spring高级45讲【第一章】：导学</div></div></a></div><div><a href="/2023/03/23/%E6%89%8B%E5%86%99%E7%AE%80%E6%98%93%E7%89%88spring-web%E6%A1%86%E6%9E%B6.html" title="手写简易版spring web框架"><img class="cover" src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/articles/%E6%89%8B%E5%86%99%E7%AE%80%E6%98%93%E7%89%88spring-web%E6%A1%86%E6%9E%B6/01cover.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-03-23</div><div class="title">手写简易版spring web框架</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://geekwolfman-blog.oss-cn-chengdu.aliyuncs.com/config/avatar/avatar.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">狼族少年、血狼</div><div class="author-info__description"></div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">9</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://wpa.qq.com/msgrd?v=3&amp;uin=2370032534&amp;site=qq&amp;menu=yes&amp;jumpflag=1"><i class="fa-brands fa-qq"></i><span>添加博主QQ</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">本站所有博文均是博主的学习笔记与个人理解，来源于网络，如有<span style="color:red;font-weight:bold;">侵权</span>请<a target="_blank" rel="noopener" href="https://wpa.qq.com/msgrd?v=3&uin=2370032534&site=qq&menu=yes&jumpflag=1" style="color:#49B1F5;font-weight:bold">联系我</a>进行删除🥰。</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%AE%B9%E5%99%A8%E6%8E%A5%E5%8F%A3"><span class="toc-number">1.</span> <span class="toc-text">容器接口</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#BeanFactory%E7%9A%84%E5%8A%9F%E8%83%BD"><span class="toc-number">1.1.</span> <span class="toc-text">BeanFactory的功能</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ApplicationContext%E7%9A%84%E6%89%A9%E5%B1%95%E5%8A%9F%E8%83%BD"><span class="toc-number">1.2.</span> <span class="toc-text">ApplicationContext的扩展功能</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#MessageSource"><span class="toc-number">1.2.1.</span> <span class="toc-text">MessageSource</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ResourcePatternResolver"><span class="toc-number">1.2.2.</span> <span class="toc-text">ResourcePatternResolver</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#EnvironmentCapable"><span class="toc-number">1.2.3.</span> <span class="toc-text">EnvironmentCapable</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#ApplicationEventPublisher"><span class="toc-number">1.2.4.</span> <span class="toc-text">ApplicationEventPublisher</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%B9%E5%99%A8%E6%8E%A5%E5%8F%A3%E6%80%BB%E7%BB%93"><span class="toc-number">1.3.</span> <span class="toc-text">容器接口总结</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%AE%B9%E5%99%A8%E5%AE%9E%E7%8E%B0"><span class="toc-number">2.</span> <span class="toc-text">容器实现</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#BeanFactory%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-number">2.1.</span> <span class="toc-text">BeanFactory的实现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ApplicationContext%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-number">2.2.</span> <span class="toc-text">ApplicationContext的实现</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Bean%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-number">3.</span> <span class="toc-text">Bean的生命周期</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Bean%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F-1"><span class="toc-number">3.1.</span> <span class="toc-text">Bean的生命周期</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.2.</span> <span class="toc-text">模板方法模式</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Bean%E5%90%8E%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-number">4.</span> <span class="toc-text">Bean后处理器</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E8%A7%81%E7%9A%84Bean%E5%90%8E%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-number">4.1.</span> <span class="toc-text">常见的Bean后处理器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BE%9D%E8%B5%96%E6%B3%A8%E8%A7%A3%E5%90%8E%E5%A4%84%E7%90%86%E5%99%A8%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-number">4.2.</span> <span class="toc-text">依赖注解后处理器执行流程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#findAutowiringMetadata"><span class="toc-number">4.2.1.</span> <span class="toc-text">findAutowiringMetadata()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#inject"><span class="toc-number">4.2.2.</span> <span class="toc-text">inject()</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#BeanFactory%E5%90%8E%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-number">5.</span> <span class="toc-text">BeanFactory后处理器</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8%E5%90%8E%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-number">5.1.</span> <span class="toc-text">常用后处理器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A8%A1%E6%8B%9F%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0"><span class="toc-number">5.2.</span> <span class="toc-text">模拟注解实现</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#ComponentScan"><span class="toc-number">5.2.1.</span> <span class="toc-text">@ComponentScan</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Bean"><span class="toc-number">5.2.2.</span> <span class="toc-text">@Bean</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Mapper"><span class="toc-number">5.2.3.</span> <span class="toc-text">@Mapper</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Aware%E6%8E%A5%E5%8F%A3"><span class="toc-number">6.</span> <span class="toc-text">Aware接口</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Aware%E4%B8%8EInitializingBean%E6%8E%A5%E5%8F%A3"><span class="toc-number">6.1.</span> <span class="toc-text">Aware与InitializingBean接口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B3%A8%E8%A7%A3%E5%A4%B1%E6%95%88%E5%88%86%E6%9E%90"><span class="toc-number">6.2.</span> <span class="toc-text">注解失效分析</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%8E%E9%94%80%E6%AF%81"><span class="toc-number">7.</span> <span class="toc-text">初始化与销毁</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E6%96%B9%E6%B3%95"><span class="toc-number">7.1.</span> <span class="toc-text">初始化方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%94%80%E6%AF%81%E6%96%B9%E6%B3%95"><span class="toc-number">7.2.</span> <span class="toc-text">销毁方法</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Scope"><span class="toc-number">8.</span> <span class="toc-text">Scope</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Scope%E7%9A%84%E7%B1%BB%E5%9E%8B%E4%B8%8E%E9%94%80%E6%AF%81"><span class="toc-number">8.1.</span> <span class="toc-text">Scope的类型与销毁</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Scope%E5%A4%B1%E6%95%88%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95"><span class="toc-number">8.2.</span> <span class="toc-text">Scope失效解决方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E5%BC%8F%E4%B8%80"><span class="toc-number">8.2.1.</span> <span class="toc-text">解决方式一</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E5%BC%8F%E4%BA%8C"><span class="toc-number">8.2.2.</span> <span class="toc-text">解决方式二</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E5%BC%8F%E4%B8%89"><span class="toc-number">8.2.3.</span> <span class="toc-text">解决方式三</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E5%BC%8F%E5%9B%9B"><span class="toc-number">8.2.4.</span> <span class="toc-text">解决方式四</span></a></li></ol></li></ol></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By 狼族少年、血狼</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><div class="js-pjax"></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="false"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></body></html>